Confusion about compound assingnments (+=, -=, *=, ...) in Java - java

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!

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.

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.

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.

x -= ((x += 1) << 1);
x = x - ((x += 1) << 1);
= 1 - ((1 + 1) << 1);
= 1 - (2 << 1)
= 1 - 4
= -3

Related

output is not what I expected because of operator precedence

int a = 6;
int b = 5;
System.out.print(a *= a++ - (a++) * b);
result out -174
I thought (a++) -> 6
and following the operation ordering, 7 - (6) * 5 => -23
then a should be now 8.
so 8 *= -23 => -184 is what I thought
Please help me out step by step which was wrong and I misunderstand.
Thanks
According to the Java Language Specification section 15.7.1,
The left-hand operand of a binary operator appears to be fully evaluated before any part of the right-hand operand is evaluated.
So in your case, the unparenthesised a++ is evaluated before (a++) * b, which makes the right hand side of the assignment equal to 6 - 7 * 5. That's equal to -29, and multiplying a by -29 gives -174.

How is A *= B *= A *= B evaluated?

public static void main(String[] args) {
int A=5;
int B=2;
A *= B*= A *= B ;
System.out.println(A);
System.out.println(B);
}
When I calculated this problem on paper I found A=200 B=20, but when I write it down to eclipse it shows A=100 B=20
Can you explain the solution like solving on the paper?
I tried to solve in Eclipse and by myself.
How do we solve it?
Starting off with A=5, B=2
A becomes A * B * A * B, which is 100, and
B becomes B * A * B, which is 20.
In more detail:
A *= B *= A *= B
is
A = A * (B = B * (A = A * B))
That resolves to
A = 5 * (B = 2 * (A = 5 * 2))
which means
A = 5 * (B = 2 * (A = 10)) // set A to 10
A = 5 * (B = 2 * 10)
A = 5 * (B = 20) // set B to 20
A = 5 * 20
A = 100 // set A to 100
This has to do with evaluation of operands taking place before order of operators (precedence).
Before operators are executed, the operands are evaluated, which in Java always take place in a left-to-right order.
The leftmost A is evaluated as 5, then the leftmost B is 2, then the second A is 5 and the second B is also 2. These values are saved for later computation.
The JLS, Section 15.26.2, deals with the procedure of evaluating a compound assignment operator.
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.
(bold emphasis mine)
Then the operators are executed, with *= having right-associativity. This means that operation proceeds right-to-left. The rightmost A *= B is executed, assigning 10 to A. The the middle B *= A is executed, assigning 20 to B. However, when the leftmost A *= B is executed, the saved value of A is still there -- 5. When multiplied by 20, 100 is assigned to A.
A *= B*= A *= B; // A is now 100
If we break this up into 3 statements, then you will get the expected 200, because A will be evaluated again as part of the last statement as 10, not 5, because the saved value for A is now 10.
A *= B;
B *= A;
A *= B; // A is now 200

Java post-increment and pre increment behaviour

I have a simple Java expression depicted below. Based on Operator Precedence table, I expect that this expression would return division by zero exception (since post-fix increment operator has highest priority) and expect that resulting expression would look like:
2 + 2 + 5 / 0
But result is 7, why ? (By little bit of experimentation I found that all operators are assigned value of 1 for some reason, but this does not make sense to me in case priority table is correct)
int intCountOperator = 0;
unaryOperand = ++intCountOperator + intCountOperator + 5 / intCountOperator++;
System.out.println(unaryOperand); // Prints 7
The operator precedence does not control the evaluation order. It controls only how the expression is to be read. For example, since multiplication has a higher precedence than addition, x + y * z is read as x + (y * z), not (x + y) * z. However, it does not change that first x is evaluated, then y and finally z.
Giving a good example with ++ and -- is more difficult, because there is usually only one reading which makes sense. However, you might notice that y - x++ compiles without error (if x and y are numerical variables). If ++ would have had a lower precedence than - it would be evaluated as (x - y)++ which would not compile.
Because of operator precedence, your expression is evaluated as:
(++intCountOperator) + (intCountOperator + (5 / (intCountOperator++)));
but the evaluation order is not changed by it.
The expression is evaluated from left to right :
unaryOperand = ++intCountOperator + intCountOperator + 5 / intCountOperator++;
1 + 1 + 5 / 1 = 7
Note that the operators are evaluated in the order you expect, i.e. 1 + 1 + (5/1) = 1 + 1 + 5 = 7, but the operands of all those expressions are evaluated from left to right.
The order of evaluation is from left to right and not right to left. So the result 7 which you are getting is correct.
unaryOperand = ++intCountOperator + intCountOperator + 5 / intCountOperator++;
is actually
unaryOperand = 1 + 1 + 5 / 1; = 7

x = x++ doesn't increment because the ++ is applied after the assignment?

From page 280 of OCP Java SE 6 Programmer Practice Exams, question 9:
int x = 3;
x = x++;
// x is still 3
In the explanation we can read that:
The x = x++; line doesn't leave x == 4 because the ++ is applied
after the assignment has occurred.
I agree that x is 3, I understand post-incremenation.
I don't agree with the explanation. I would replace "after" with "before".
I thought it works like this:
x is 3.
x++ is executed. I see this post-increment operator as a function:
int operator++() {
int temp = getX();
setX(temp + 1);
return temp;
}
So, after x++ execution, x is 4, but the value returned from x++ expression is 3.
Now, the assignment =. Simply write returned 3 to x.
So, in my eyes ++ is applied before the assignment has occurred. Am I wrong?
...the ++ is applied after the assignment has occurred.
Okay, hold on. This is actually confusing and perhaps suggests an incorrect behavior.
You have the expression†:
x = ( x++ )
What happens is (JLS 15.26.1):
The expression on the left-hand side of the assignment x is evaluated (to produce a variable).
The expression on the right-hand side of the assignment ( x++ ) is evaluated (to produce a value).
The evaluation of the right-hand side is: x is post-incremented, and the result of the expression is the old value of x.
The variable on the left-hand side, x, is assigned the value produced by the evaluation of the right-hand side, which is the old value of x.
So the post-increment happens before the assignment.
(Therefore, as we know, the value of x after executing the statement x = x++; is the same as the value of x before executing the statement, which is 3.)
So, in my eyes ++ is applied before the assignment has occurred. Am I wrong?
You are right.
Technically, the way it is specified is that x++ is evaluated before its result is stored and during the evaluation of the assignment operator. So x++ can be interpreted as happening either before or during the assignment. Not after, so the book appears to be wrong either way.
Just for the heck of it, we may also look at some bytecode:
/* int x = 3; */
iconst_3 // push the constant 3 on to the stack : temp = 3
istore_0 // pop the stack and store in local variable 0 : x = temp
/* x = x++; */
iload_0 // push local variable 0 on to the stack : temp = x
iinc 0 1 // increment local variable 0 by 1 : x = x + 1
istore_0 // pop the stack and store in local variable 0 : x = temp
The iinc happens before the istore.
†: The parentheses have no effect on the evaluation, they are just there for clarity.
Reaching over to the official spec:
postfix ++ section: https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.14.2
assignment operator section: https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.26.1
In terms of assignment, this is simple assignment, so we hit case 3:
First, the left-hand operand is evaluated to produce a variable -- x
no errors -> the right-hand operand is evaluated -- x++
"the value of the right-hand operand is converted to the type of the left-hand variable, is 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 in step 2, the postfix operator should get resolved, and then in step 3, x gets assigned its original value again:
call: x = x++;
interframe: LHS is variable 'x'
interframe: RHS caches return value as 3
interframe: x is incremented to 4
interframe: RHS cached value '3' is returned for assignment
interframe: variable x is assigned value 3
call result: x = 3
So I think you're right in that the book is wrong, and it might be worth contacting the authors or publisher to have a correction published (or added to an errata page, etc)
x++ means "use x and then increment x."
You can also use ++x, which means "increment x and then use x."
More easily, however, you can simply do
x += 1;
++x is called preincrement while x++ is called postincrement.
int x = 3;
x = ++x;
exemple
int x = 5, y = 5;
System.out.println(++x); // outputs 6
System.out.println(x); // outputs 6
System.out.println(y++); // outputs 5
System.out.println(y); // outputs 6

Logical Operator Precedence

Through Java operator precedence table:
'|' Logical OR operator has higher precedence than '&&' logical AND operator.
I checked above fact using following code
int y = 5;
int x = 2;
if( x++ > 2 && ++y > 2 | true )
; //do nothing
System.out.println("x = " + x + " y = " + y);
but above line giving output as -
x = 3 y = 5
showing that x++ is evaluating first.
Even I put parentheses at condition around |
if( x++ > 2 && (++y > 2 | true) )
;
But still I am getting the same output.
Why operator precedence not working in this case?
That's not the logical operator. That's the bitwise operator. It will evaluate everything - that is, it won't short circuit - and if anything flips that bit to 1, it'll stay at 1 until negated.
Here's how these statements would evaluate:
x++ > 2 && ++y > 2 || true -> true. We fail with the logical AND, but succeed with the logical OR. With short circuiting, we don't continue to evaluate any portion of the logical AND, since x > 2 is false.
x++ > 2 && (++y > 2 || true) -> false, since we will short-circut due to x > 2 not being true.
If you actually don't want the short circuit behavior, then use the bitwise AND as well, and you'll get your expected evaluation block.
x++ > 2 & ++y > 2 | true will still evaluate to true, but the values of x and y will change to 3 and 6, respectively.
| is the bitwise OR operator. You're looking for ||. It's similar, but differs in that it has higher precedence and does not apply short circuit evaluation.
I see what you're really asking now. You're wondering why if && has the least precedence, the rest of the statement isn't evaluated before finally coming to it. So in
x++ > 2 && ++y > 2 | true
it should evaluate x++ > 2, then ++y > 2 | true and finally apply &&. Well, the answer is that && applies short circuit evaluation. Sure, it can evaluation everything and then apply its effect, and that's what the bitwise operator does. However it doesn't because
if (a && b && ...)
is supposed to behave similarly to
if (a) {
if (b) {
...
}
}
Operator precedence is as you expect, however, the evaluation is terminated early because of the property of the operator. So going back to
x++ > 2 && ++y > 2 | true
We see that x++ > 2 is false, so ++y > 2 | true is not evaluated.
try this
if( x++ > 2 && ++y > 2 || true )
You are using bitwise operator not logical operator
Operators in java
Even if the operator | has higher precedence, the operator isn't even discovered at the point where the program checks if calculating the right-hand side (of &&) is necessary.
Consider the statement (true && true | true). This is how it is calculated:
Check (true && ...) to see if further operations are necessary, (which is the case).
Higher precedence: Perform the operation (true | true) -> true.
Lower precedence: Perform the operation (true && true) -> true.
In your case, since (x++ > 2) gives false, the right-hand side of && is never even touched.
Since whatever you place the braces , it will start from left to right because it in case of && , it is optimized to check first condition , it get false , then why to go to second condition , no matter braces are there ,secondly x++ will get executed , condition get false , so it is printing the same output but when you do let say using ||
class Test{
public static void main(String[] args) {
int x=2,y=5;
if( x++ > 2 || (++y > 2 | true) )
;
System.out.println(x +" "+y );
}
}
It will print 3 6 because || takes place , first condition get false but when it comes to second , ++y > 2 evaluated to true | between boolean values give output on basis of bitwise OR , true OR true is true .
The logical operators: (&& , ||, &, |, and ^) can be used only to evaluate two
boolean expressions.
The difference between && and & is that the && operator
won't bother testing the right operand if the left evaluates to false, because the
result of the && expression can never be true.
The difference between || and | is
that the || operator won't bother testing the right operand if the left evaluates to
true, because the result is already known to be true at that point.
Bitwise operators: (&, |, and ^) can also be called as "Bitwise" operators. Bitwise operators compare two variables bit by bit, and return a variable
whose bits have been set based on whether the two variables being compared had
respective bits that were either both "on" (&), one or the other "on" (|), or exactly
one "on" (^).

Categories