Why does (x += x += 1) evaluate differently in C and Javascript? Why does (x += x += 1) evaluate differently in C and Javascript? javascript javascript

Why does (x += x += 1) evaluate differently in C and Javascript?


x += x += 1; is undefined behavior in C.

The expression statement violates sequence points rules.

(C99, 6.5p2) "Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression."


JavaScript and Java have pretty much strict left-to-right evaluation rules for this expression. C does not (even in the version you provided that has the identity function intervening).

The ECMAScript spec I have (3rd Edition, which I'll admit is quite old – the current version can be found here: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf) says that compound assignment operators are evaluated like so:

11.13.2 Compound Assignment ( op= )

The production AssignmentExpression : LeftHandSideExpression @ = AssignmentExpression, where@ represents one of the operators indicated above, is evaluated as follows:

  1. Evaluate LeftHandSideExpression.
  2. Call GetValue(Result(1)).
  3. Evaluate AssignmentExpression.
  4. Call GetValue(Result(3)).
  5. Apply operator @ to Result(2) and Result(4).
  6. Call PutValue(Result(1), Result(5)).
  7. Return Result(5)

You note that Java has the same behavior as JavaScript – I think its spec is more readable, so I'll post some snippets here (http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.7):

15.7 Evaluation Order

The Java programming language guarantees that the operands of operators appear to be evaluated in a specific evaluation order, namely, from left to right.

It is recommended that code not rely crucially on this specification. Code is usually clearer when each expression contains at most one side effect, as its outermost operation, and when code does not depend on exactly which exception arises as a consequence of the left-to-right evaluation of expressions.

15.7.1 Evaluate Left-Hand Operand First The left-hand operand of a binary operator appears to be fully evaluated before any part of the right-hand operand is evaluated. For example, if the left-hand operand contains an assignment to a variable and the right-hand operand contains a reference to that same variable, then the value produced by the reference will reflect the fact that the assignment occurred first.

...

If the operator is a compound-assignment operator (§15.26.2), then evaluation of the left-hand operand includes both remembering the variable that the left-hand operand denotes and fetching and saving that variable's value for use in the implied combining operation.

On the other hand, in the not-undefined-behavior example where you provide an intermediate identity function:

x += id(x += 1);

while it's not undefined behavior (since the function call provides a sequence point), it's still unspecified behavior whether the leftmost x is evaluated before the function call or after. So, while it's not 'anything goes' undefined behavior, the C compiler is still permitted to evaluate both x variables before calling the id() function, in which case the final value stored to the variable will be 1:

For example, if x == 0 to start, the evaluation could look like:

tmp = x;    // tmp == 0x = tmp  +  id( x = tmp + 1)// x == 1 at this point

or it could evaluate it like so:

tmp = id( x = x + 1);   // tmp == 1, x == 1x = x + tmp;// x == 2 at this point

Note that unspecified behavior is subtly different than undefined behavior, but it's still not desirable behavior.


In C, x += x += 1 is undefined behavior.

You can not count on any result happening consistently because it is undefined to try to update the same object twice between sequence points.