Reputation: 11
I'm a little confused about the result of the following code:
int x = 1;
x -= ((x += 1) << 1);
System.out.println(x);
It prints out -3
, but I'd expected it to print out -2
, because in my head the computation should go like this:
| Opearation | Returned | x |
+------------+----------+---+
| int x = 1; | - | 1 |
+------------+----------+---+
| (x += 1) | 2 | 2 |
+------------+----------+---+
| (2 << 1) | 4 | 2 |
+------------+----------+---+
| x -= 4; | - |-2 |
What am I missing here? Can somebody please explain to me what's going on?
Thanks!
Upvotes: 0
Views: 136
Reputation: 4187
Value of x (=1) is populated on the RHS of the expression before the sub-expression (x+=1) is processed hence leftmost x is substituted as 1 way before it is processed in x+=1 which results into 2. Hence it will be ...
x = 1 - ((x=1+1) << 1)
x = 1 - ((x=2) << 1)
x = 1 - (2 << 1)
x = 1 - 4
x = -3
Here x=2 results into 2 as assignment operator returns same value as assigned to the variable.
Upvotes: 0
Reputation: 77226
Unlike some other languages (looking at you, C++), the Java Language Specification guarantees that expression operands are evaluated left-to-right:
The Java programming language guarantees that the operands of operators appear to be evaluated in a specific evaluation order, namely, from left to right.
Let's unroll your compound statement:
x -= ((x += 1) << 1);
x = x - ((x = x + 1) << 1);
^
The x
with the arrow is evaluated first, which means that the assignment that happens later within the expression doesn't affect the value (in this case, the JVM stack already has a 1
on it). The rest of the evaluation proceeds as you expect, but the final operation is 1 - 4 = -3
.
Note that right after the statement above, the JLS also includes a note that absolutely applies here:
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.
Upvotes: 0
Reputation: 6333
JLS 15.26.2 says following, https://docs.oracle.com/javase/specs/jls/se9/html/jls-15.html#jls-15.26.2
If the left-hand operand expression is not an array access expression, then:
First, the left-hand operand is evaluated to produce a variable. If this evaluation completes abruptly, then the assignment expression completes abruptly for the same reason; the right-hand operand is not evaluated and no assignment occurs.
Otherwise, the value of the left-hand operand is saved and then the right-hand operand is evaluated. If this evaluation completes abruptly, then the assignment expression completes abruptly for the same reason and no assignment occurs.
Otherwise, the saved value of the left-hand variable and the value of the right-hand operand are used to perform the binary operation indicated by the compound assignment operator. If this operation completes abruptly, then the assignment expression completes abruptly for the same reason and no assignment occurs.
Otherwise, the result of the binary operation is converted to the type of the left-hand variable, subjected to value set conversion (§5.1.13) to the appropriate standard value set (not an extended-exponent value set), and the result of the conversion is stored into the variable.
So the original value of x
, i.e. 1, is saved, then the RHS is evaluated. Therefore it's -3
.
Upvotes: 3
Reputation: 15714
x -= ((x += 1) << 1);
x = x - ((x += 1) << 1);
= 1 - ((1 + 1) << 1);
= 1 - (2 << 1)
= 1 - 4
= -3
Upvotes: -1