简体   繁体   中英

Operator precedence

Consider this C# class:

class Node
{
    public Node Next;
}

And consider these 2 cases:

        Node A = new Node();
        Node B = A;
        B=(B.Next = new Node());

and

        Node A = new Node();
        Node B = A;
        B.Next = (B=new Node());

Why do they produce the same results!?
(A)->(B)->Null

I thought the 2nd case would produce a node pointing to itself because of operator precedence...

Is that the case in Java and Python too? Thanks

In Python, you cannot group assignments in the way you have done. The extreme RHS value is assigned to all the identifiers towards it's left.

>>> a = (b=42)
  File "<stdin>", line 1
    a = (b=42)
          ^
SyntaxError: invalid syntax
>>> a = b = 42

>>> print a,b
42 42
>>> 

Similar to your question

>>> class Node():
...     def __init__(self):
...             self.next = self
... 
>>> n = Node()
>>> n = n.next = Node()
>>> n
<__main__.Node instance at 0x7f07c98eb200>
>>> n.next = n = Node()
>>> n
<__main__.Node instance at 0x7f07c98eb290>

C# evaluates the sides of the assignment from left to right.

So in your second case it is 'evaluating' the LHS (B.Next) in the assignment on the last line before it evaluates the RHS, and arriving at the reference to Next in A.

Whatever you do on the RHS is assigned to this. So changing B on the RHS is too late.

If it didn't do this then

B.Next = (B = null)

Would be a null reference exception which wouldn't be what you would expect would it?

This behavior is not a result of operator precedence, but of rules in Java, Python, and C# which define the order of evaluation of expressions. Specifically, in Java, Python, and C#, expressions are evaluated left to right. This isn't true, for example, in C and C++, where the result of what you wrote would have been undefined.

You might be familiar with this C puzzle:

int i = 1;
printf("%d, %d\n", i++, ++i); // what is printed?

In C, the result is not defined. It could be 1, 3 , it could be 2, 2 , or even something else. In Java C#, and Python, the result is always 1, 3 (except of course that Python does not have a pre- or postfix ++ operator).

Operator precedence is a separate issue. It defines the parse tree, not the order of evaluation.

Say you had a new language with binary infix operators op1 and op2 . And say you had the following piece of code:

e1 op1 e2 op2 e3

Operator precedence tells you whether this means

((e1 op1 e2) op2 e3)

Or whether it means

(e1 op1 (e2 op2 e3))

It does not tell you the order in which e1 , e2 , and e3 are evaluated.

For completeness, Java works here the same like C#.

    Node A = new Node();

Creates a new node (let's name it Node 1), and lets A point to it.

    Node B = A;

This lets B point to the same Node 1.

A ----> [Node 1]---> null
           ↑
B −−−−−−−−−'

This is the situation now. So, now the complicated last line:

    B.Next = 

This changes the next-pointer of Node 1 (to which B pointed) to ...

       (B=new Node());

... a new node (lets call it Node 2), which is at the same time put into the B variable.

A ----> [Node 1]---> [Node 2]----> null
                         ↑
B −−−−−−−−−−−−−−−−−−−−−−−'

The interesting thing here is, that the B.next is evaluated before the right side of the assignment, so it is the same as if you wrote A.next here.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM