Why is x == (x = y) not the same as (x = y) == x?

Consider the following example:

class Quirky {
    public static void main(String[] args) {
        int x = 1;
        int y = 3;

        System.out.println(x == (x = y)); // false
        x = 1; // reset
        System.out.println((x = y) == x); // true
     }
}

I'm not sure if there is an item in the Java Language Specification that dictates loading the previous value of a variable for comparison with the right side (x = y) which, by the order implied by brackets, should be calculated first.

Why does the first expression evaluate to false, but the second evaluate to true? I would have expected (x = y) to be evaluated first, and then it would compare x with itself (3) and return true.


This question is different from order of evaluation of subexpressions in a Java expression in that x is definitely not a 'subexpression' here. It needs to be loaded for the comparison rather than to be 'evaluated'. The question is Java-specific and the expression x == (x = y), unlike far-fetched impractical constructs commonly crafted for tricky interview questions, came from a real project. It was supposed to be a one-line replacement for the compare-and-replace idiom

int oldX = x;
x = y;
return oldX == y;

which, being even simpler than x86 CMPXCHG instruction, deserved a shorter expression in Java.


== is a binary equality operator.

The left-hand operand of a binary operator appears to be fully evaluated before any part of the right-hand operand is evaluated.

Java 11 Specification > Evaluation Order > Evaluate Left-Hand Operand First


As LouisWasserman said, the expression is evaluated left to right. And java doesn't care what "evaluate" actually does, it only cares about generating a (non volatile, final) value to work with.

//the example values
x = 1;
y = 3;

So to calculate the first output of System.out.println(), the following is done:

x == (x = y)
1 == (x = y)
1 == (x = 3) //assign 3 to x, returns 3
1 == 3
false

and to calculate the second:

(x = y) == x
(x = 3) == x //assign 3 to x, returns 3
3 == x
3 == 3
true

Note that the second value will always evaluate to true, regardless of the initial values of x and y, because you are effectively comparing the assignment of a value to the variable it is assigned to, and a = b and b will, evaluated in that order, always be the same by definition.


which, by the order implied by brackets, should be calculated first

No. It is a common misconception that parentheses have any (general) effect on calculation or evaluation order. They only coerce the parts of your expression into a particular tree, binding the right operands to the right operations for the job.

(And, if you don't use them, this information comes from the "precedence" and associativity of the operators, something that's a result of how the language's syntax tree is defined. In fact, this is still exactly how it works when you use parentheses, but we simplify and say that we're not relying on any precedence rules then.)

Once that's done (i.e. once your code has been parsed into a program) those operands still need to be evaluated, and there are separate rules about how that is done: said rules (as Andrew has shown us) state that the LHS of each operation is evaluated first in Java.

Note that this is not the case in all languages; for example, in C++, unless you're using a short-circuiting operator like && or ||, the evaluation order of operands is generally unspecified and you shouldn't rely on it either way.

Teachers need to stop explaining operator precedence using misleading phrases like "this makes the addition happen first". Given an expression x * y + z the proper explanation would be "operator precedence makes the addition happen between x * y and z, rather than between y and z", with no mention of any "order".


I'm not sure if there is an item in the Java Language Specification that dictates loading the previous value of a variable...

There is. Next time you are unclear what the specification says, please read the specification and then ask the question if it is unclear.

... the right side (x = y) which, by the order implied by brackets, should be calculated first.

That statement is false. Parentheses do not imply an order of evaluation. In Java, the order of evaluation is left to right, regardless of parentheses. Parentheses determine where the subexpression boundaries are, not the order of evaluation.

Why does the first expression evaluate to false, but the second evaluate to true?

The rule for the == operator is: evaluate the left side to produce a value, evaluate the right side to produce a value, compare the values, the comparison is the value of the expression.

In other words, the meaning of expr1 == expr2 is always the same as though you had written temp1 = expr1; temp2 = expr2; and then evaluated temp1 == temp2.

The rule for the = operator with a local variable on the left side is: evaluate the left side to produce a variable, evaluate the right side to produce a value, perform the assignment, the result is the value that was assigned.

So put it together:

x == (x = y)

We have a comparison operator. Evaluate the left side to produce a value -- we get the current value of x. Evaluate the right side: that's an assignment so we evaluate the left side to produce a variable -- the variable x -- we evaluate the right side -- the current value of y -- assign it to x, and the result is the assigned value. We then compare the original value of x to the value that was assigned.

You can do (x = y) == x as an exercise. Again, remember, all the rules for evaluating the left side happen before all the rules of evaluating the right side.

I would have expected (x = y) to be evaluated first, and then it would compare x with itself (3) and return true.

Your expectation is based on a set of incorrect beliefs about the rules of Java. Hopefully you now have correct beliefs and will in the future expect true things.

This question is different from "order of evaluation of subexpressions in a Java expression"

This statement is false. That question is totally germane.

x is definitely not a 'subexpression' here.

This statement is also false. It is a subexpression twice in each example.

It needs to be loaded for the comparison rather than to be 'evaluated'.

I have no idea what this means.

Apparently you still have many false beliefs. My advice is that you read the specification until your false beliefs are replaced by true beliefs.

The question is Java-specific and the expression x == (x = y), unlike far-fetched impractical constructs commonly crafted for tricky interview questions, came from a real project.

The provenance of the expression is not relevant to the question. The rules for such expressions are clearly described in the specification; read it!

It was supposed to be a one-line replacement for the compare-and-replace idiom

Since that one-line replacement caused a great deal of confusion in you, the reader of the code, I would suggest that it was a poor choice. Making the code more concise but harder to understand is not a win. It is unlikely to make the code faster.

Incidentally, C# has compare and replace as a library method, which can be jitted down to a machine instruction. I believe Java does not have such a method, as it cannot be represented in the Java type system.


It is related to operator precedence and how operators are getting evaluated.

Parentheses '()' has higher precedence and has associativity left to right. Equality '==' come next in this question and has associativity left to right. Assignment '=' come last and has associativity right to left.

System use stack to evaluate expression. Expression gets evaluated left to right.

Now comes to original question:

int x = 1;
int y = 3;
System.out.println(x == (x = y)); // false

First x(1) will be pushed to stack. then inner (x = y) will be evaluated and pushed to stack with value x(3). Now x(1) will be compared against x(3) so result is false.

x = 1; // reset
System.out.println((x = y) == x); // true

Here, (x = y) will be evaluated, now x value become 3 and x(3) will be pushed to stack. Now x(3) with changed value after equality will be pushed to stack. Now expression will be evaluated and both will be same so result is true.