Java Assignments are evaluated Left to Right

I think I’ve just found a mistake in the Java Tutorial.

Maybe I’m just being pedantic, but I think I’ve just found a mistake in the Java Tutorial. It claims:

All binary operators except for the assignment operators are evaluated from left to right; assignment operators are evaluated right to left.

The Java™ Tutorials » Language Basics » Operators

What is this supposed to mean? Evaluation from right to left would mean that when you have a line like the following you get the rightmost expression evaluated first:

int x = 42;
x += getNumber();
// The above would be equivalent to:
x = getNumber() + x;

But that’s not how Java actually evaluates this expression. And the JLS 12 (2019-02-08) clearly states in 15.26.2 that “the value of the left-hand operand is saved and then the right-hand operand is evaluated.”

This explains it best:

A compound assignment expression of the form E1 op= E2 is equivalent to E1 = (T) ((E1) op (E2)), where T is the type of E1, except that E1 is evaluated only once.

JLS 12, 15.26.2 Compound Assignment Operators

So the above code is actually equal to this:

x = (int) (x + getNumber());

Addition is commutative, so it doesn’t matter. But we also have /=, which is not commutative. You can test this by using a static field for x and some side effect (such as System.out.println and some assignment to x) in getNumber().

public class SomeClass {
	static int x = 42;

	public static void main(String[] args) {
		// assignment operators are evaluated right to left?
		x += getNumber();
		// equal to:
		// x = x + getNumber();
		System.out.println(x);
	}

	static int getNumber() {
		System.out.println("wahr!");
		x = Integer.MIN_VALUE;
		return 58;
	}
}

This code will print 100. That’s because the old value of x (42) is used. If x was evaluated after getNumber() you would get -2147483590 instead.

Contrary to that the Tutorial says all assignments are evaluated left to right. But all the assignment operators are  right-associative. That might be the reason for the mix-up.

There are 12 assignment operators; all are syntactically right-associative (they group right-to-left). Thus, a=b=c means a=(b=c), which assigns the value of c to b and then assigns the value of b to a.

JLS 12, 15.26 Assignment Operators

Example:

public static void main(String[] args) {
	int x = 42, y = 58;
	x += y *= x;
	// equal to: 
	// x = x + (y = y*x);
	System.out.println(x);
}

It would not make any sense if they were left-associative.

The Tutorial should be corrected to say:

All binary operators except for the assignment operators are grouped from left to right; assignment operators are grouped right to left.

Or:

All binary operators except for the assignment operators are left-associative; assignment operators are right-associative.