I don`t understand how Java is progressing this arithmetic expression
int x = 1;
int y = 1;
x += y += x += y;
System.out.println("x=" + x + " y=" + y);
With Java I get x = 4 and y = 3. But in C, Perl, Php I get x=5 and y = 3
On the paper I also get x = 5 and y = 3
This is the nasty part, obviously:
x += y += x += y;
This is executed as:
int originalX = x; // Used later
x = x + y; // Right-most x += y
y = y + x; // Result of "x += y" is the value stored in x
x = originalX + y; // Result of "y += x" is the value stored in y
So:
x y
(Start) 1 1
x = x + y 2 1
y = y + x 2 3
x = originalX + y 4 3
The important part is the use of originalX here. The compound assignment is treated as:
x = x + y
and the first operand of + is evaluated before the second operand... which is why it takes the original value of x, not the "latest" one.
From JLS section 15.16.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.
When in doubt, consult the language specification - and never assume that just because two languages behave differently, one of them is "wrong". So long as the actual behaviour matches the specified behaviour for each language, all is well - but it does mean you need to understand the behaviour of each language you work with, of course.
That said, you should clearly avoid horrible code like this in the first place.
it starts from right to left
1. x += y gives x = 2, y = 1
2. y += ( x +=y ) gives x = 2, y = 3
3. x += ( y += x += y ) gives x = 4, y = 3
so, it's all consistent
Related
I playing around with Java and I have come across this. I am wondering why this gives the result of 7.0:
float x = 3f;
int y = 4;
System.out.println(x+++y); // 7.0
And not 8.0, like it does here when we use brackets?
System.out.println(x+(++y)); // 8.0
Your first example evaluates to x++ + y but your second example evaluates to, as expected, x + ++y
x++ + y
Extract the value from x // x = 3
Extract the value from y // y = 4
Add them // sum = 7
Add 1 to x // x = 4
x + ++y
Extract the value from x // x = 3
Add 1 to y // y = 5
Extract the value from y // y = 5
Add them // sum = 8
Java thinks you're trying to do a (x++ + y) inside the println.
So it first use the x as it is to add it with y and then apply the ++ to the x.
Java goes from left to right.
I'm trying to swap two ints - x and y in the example, and do it in one line without a library function.
So I started with this:
int x = 4;
int y = 3;
System.out.println(x);
System.out.println(y);
x ^= y;
System.out.println(x);
System.out.println(y);
y ^= x;
System.out.println(x);
System.out.println(y);
x ^= y;
System.out.println(x);
System.out.println(y);
The output was 4, 3, 7, 3, 7, 4, 3, 4 as expected. All good so far.
Next up was this:
int x = 4;
int y = 3;
System.out.println(x);
System.out.println(y);
y ^= (x ^= y);
System.out.println(x);
System.out.println(y);
x ^= y;
System.out.println(x);
System.out.println(y);
The output was 4, 3, 7, 4, 3, 4 as expected once again. Still good so far.
Then finally this:
int x = 4;
int y = 3;
System.out.println(x);
System.out.println(y);
x ^= (y ^= (x ^= y));
System.out.println(x);
System.out.println(y);
At this stage the output became 4, 3, 0, 4. Now I know that the 0 is a result of 4 ^ 4 because the x assignment wasn't complete at that time - why is this happening? Why doesn't the x ^= y actually assign 7 to the x variable so that it becomes 7 ^ 4 for the last assignment?
Let's try to expand your last expression.
It evaluates to,
x = x^(y = y^ (x = x^y));
Note that expressions are evaluated from left to right,
it becomes,
x = 4 ^ (y = 3 ^ (x = 4 ^ 3));
Now, the problem has become obvious. Right?
Edit:
To clear come confusion, let me try to explain what I mean by evaluating from left to right.
int i = 1;
s = i + (i = 2) + i;
Now, the expression will evaluate to,
s = 1 + 2 + 2;
Notice that i on the left of assignment was 1, but on the right of assignment (and on the assigment) was evaluated to 2, because the evaluation is from left to right, when it came to the 2nd and 3rd part of the expression, is value was 2.
The order of evaluation is defined in chapter 15 of the JLS. Item 15.7.1 says:
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 binary operation.
To explain further, they have two examples of computations that involve assignments. Here the assignment is on the left hand of the operator:
int i = 2;
int j = (i=3) * i;
System.out.println(j);
And they specifically say that the result is 9 and is not allowed to be 6. That is, the (i=3) is both calculated as 3 and i is assigned 3 before being multiplied with itself.
But in the second example:
int a = 9;
a += (a = 3); // first example
System.out.println(a);
int b = 9;
b = b + (b = 3); // second example
System.out.println(b);
The JLS specifies that both prints should produce 12, and are not allowed to produce 6. That is, because the assignment to b is on the right side, the value of the left b (or the implicit left a in the += operation), the value before that assignment is fetched and saved first, and only then the operation inside the parentheses is performed.
Internally, expressions are broken down into JVM operations that push and pop values onto an "operand stack". If you think about it like that - that in b = b + (b=3) The value of b is first pushed onto the operand stack, then the (b=3) is performed and its value is then added to the value popped from the stack (old value of b), it will make sense. At this point, the left hand b just stands for "What the value of b was when it was pushed on the stack" and not for the "current value of b".
Lets divide and compute.
The innermost parenthesis executes first and after all the parenthesis resolved, then the expression executes from left to right.
x ^= (y ^= (x ^= y)); // initial statement
x = x^(y = y^ (x = x^y)); //equals to
() have the highest precedence
x = x^(y = y^ (x = 3^4)); // first highest precedence ()
x = x^(y = y ^ (x = 7)); // still the first x is 3
x = 4 ^(y = 3 ^ (x = 7)); // now 3 ^ 7 =4
x = 4 ^ 4; // now 3 ^ 7 =4
x= 0;
I just tested the following code:
int x = 90;
x = x - (x = x - 1);
System.out.print(x);
It prints 1.
As far as I understand, things go in the following order:
x - 1 is computed and stored to a temporary variable in memory.
x is assigned the result from the temporary variable from item 1.
Then x - the new value of x is calculated.
The result is assigned to x;
I don't understand why x from which we subtract the result of item 2 still has initial value after item 2. What am I missing?
From https://docs.oracle.com/javase/tutorial/java/nutsandbolts/operators.html
All binary operators except for the assignment operators are evaluated from left to right; assignment operators are evaluated right to left.
You are doing 90 - (90 - 1) => 1
It's important to not confuse precedence with order of evaluation. They are related but not the same.
EDIT
As #ruakh points out, the JLS spec put it differently to the tutorial above.
http://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.7.
The left-hand operand of a binary operator appears to be fully evaluated before any part of the right-hand operand is evaluated.
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 binary operation.
If evaluation of the left-hand operand of a binary operator completes abruptly, no part of the right-hand operand appears to have been evaluated.
Rather than say the assignment is evaluated right to left, it treats assignment as first a store of the variable to be updated, then an evaluation of the value and finally an assignment.
We start with:
int x = 90;
x = x - (x = x - 1);
The first assignment operator = has low precedence, so the right side is evaluated first.
The right side of x = x - (x = x - 1) is x - b where b is (x = x - 1)
This right side is evaluated left to right, so it becomes 90 - b
Then b, which is (x = x - 1), is evaluated. Once again the assignment operator has lowest precedence, so it becomes (x = 90 - 1) or (x = 89)
Substituting back, we have 90 - (x = 89) which is 90 - 89 which is 1. Finally, the first assignment operator is evaluated and x becomes 1. You'll notice that the other assignment operator (x = 89) had no effect on the overall operation.
int x = 90;
x = x - (x = x - 1);
System.out.print(x);`
Here
x = 90 Goes in two section in your code.
First x=90 - , Second (x=90-1);
Then x=90 - , x = 89
Then x= 90 - 89
System.out.Print(x);
that is x=1;
Consider the following pseudo-code:
int x = 10;
int y = 10;
x = x + x++;
y = y++ + y;
print(x); // 20
print(y); // 21
C-like programming languages like C# or Java say that increment has higher precedence, than + operator. So it should be 21 in both cases.
Why does it print two different results?
Remember we work from left to right.
Let's deal with x first then y.
x
x = x + x++;
We are going from left to right...
x = 10 + (10++)
Note: As we go from left to right the post increment operator on x on the far right has no effect on the x which appears first on the RHS.
x = 20
y
y = y++ + y;
y = 10++ + 11;
Again we go from left to right, the increment operator post increments y from 10 to 11, hence the y on the far right becomes 11, thus yielding (10 + 11) = 21.
When y++ + y is evaluated, y++ is evaluated before y. So the left hand side is evaluated to 10, and the right hand side will be evaluated to 11 due to the previous incrementation.
When x + x++ is evaluated, x is evaluated before x++. So both sides will be evaluated to 10, then x will be evaluated to 11 just before the = operand will evaluate x to 20.
I believe the + operator has higher precedence than ++, so the + operator is evaluated first, but in order to evaluate it - it must evaluate the left and right operators of it.
In the second example the left operator is evaluated first so y increments before the right hand is evaluated.
In the Precedence and Order of Evaluation documentation, you can see that + is above += which is basically what ++ is. Above the + is the prefix ++ which is not to be confused with the postfix ++.
I'm trying to swap two ints - x and y in the example, and do it in one line without a library function.
So I started with this:
int x = 4;
int y = 3;
System.out.println(x);
System.out.println(y);
x ^= y;
System.out.println(x);
System.out.println(y);
y ^= x;
System.out.println(x);
System.out.println(y);
x ^= y;
System.out.println(x);
System.out.println(y);
The output was 4, 3, 7, 3, 7, 4, 3, 4 as expected. All good so far.
Next up was this:
int x = 4;
int y = 3;
System.out.println(x);
System.out.println(y);
y ^= (x ^= y);
System.out.println(x);
System.out.println(y);
x ^= y;
System.out.println(x);
System.out.println(y);
The output was 4, 3, 7, 4, 3, 4 as expected once again. Still good so far.
Then finally this:
int x = 4;
int y = 3;
System.out.println(x);
System.out.println(y);
x ^= (y ^= (x ^= y));
System.out.println(x);
System.out.println(y);
At this stage the output became 4, 3, 0, 4. Now I know that the 0 is a result of 4 ^ 4 because the x assignment wasn't complete at that time - why is this happening? Why doesn't the x ^= y actually assign 7 to the x variable so that it becomes 7 ^ 4 for the last assignment?
Let's try to expand your last expression.
It evaluates to,
x = x^(y = y^ (x = x^y));
Note that expressions are evaluated from left to right,
it becomes,
x = 4 ^ (y = 3 ^ (x = 4 ^ 3));
Now, the problem has become obvious. Right?
Edit:
To clear come confusion, let me try to explain what I mean by evaluating from left to right.
int i = 1;
s = i + (i = 2) + i;
Now, the expression will evaluate to,
s = 1 + 2 + 2;
Notice that i on the left of assignment was 1, but on the right of assignment (and on the assigment) was evaluated to 2, because the evaluation is from left to right, when it came to the 2nd and 3rd part of the expression, is value was 2.
The order of evaluation is defined in chapter 15 of the JLS. Item 15.7.1 says:
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 binary operation.
To explain further, they have two examples of computations that involve assignments. Here the assignment is on the left hand of the operator:
int i = 2;
int j = (i=3) * i;
System.out.println(j);
And they specifically say that the result is 9 and is not allowed to be 6. That is, the (i=3) is both calculated as 3 and i is assigned 3 before being multiplied with itself.
But in the second example:
int a = 9;
a += (a = 3); // first example
System.out.println(a);
int b = 9;
b = b + (b = 3); // second example
System.out.println(b);
The JLS specifies that both prints should produce 12, and are not allowed to produce 6. That is, because the assignment to b is on the right side, the value of the left b (or the implicit left a in the += operation), the value before that assignment is fetched and saved first, and only then the operation inside the parentheses is performed.
Internally, expressions are broken down into JVM operations that push and pop values onto an "operand stack". If you think about it like that - that in b = b + (b=3) The value of b is first pushed onto the operand stack, then the (b=3) is performed and its value is then added to the value popped from the stack (old value of b), it will make sense. At this point, the left hand b just stands for "What the value of b was when it was pushed on the stack" and not for the "current value of b".
Lets divide and compute.
The innermost parenthesis executes first and after all the parenthesis resolved, then the expression executes from left to right.
x ^= (y ^= (x ^= y)); // initial statement
x = x^(y = y^ (x = x^y)); //equals to
() have the highest precedence
x = x^(y = y^ (x = 3^4)); // first highest precedence ()
x = x^(y = y ^ (x = 7)); // still the first x is 3
x = 4 ^(y = 3 ^ (x = 7)); // now 3 ^ 7 =4
x = 4 ^ 4; // now 3 ^ 7 =4
x= 0;