Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java operator precendece confusion && and ++

&& is a short-circuit operator evaluated from left to right, so if the operand on the left side of && operator is evaluated to false, evaluation should not continue. BUT I expected that the ++ should be evaluated before && because it has higher precedence, and (from the link):

Operators with higher precedence are evaluated before operators with relatively lower precedence.

In that case, why doesn't count increment in the third line of this code?

int mask = 2;
int count = 0;
if( !(mask > 1) && ++count > 1) { mask += 100; }
System.out.println(mask + " " + count);
like image 219
Péter Szakszon Avatar asked Dec 28 '13 10:12

Péter Szakszon


People also ask

What is the order of precedence of operators in Java?

The operator precedence is responsible for evaluating the expressions. In Java, parentheses() and Array subscript[] have the highest precedence in Java. For example, Addition and Subtraction have higher precedence than the Left shift and Right shift operators.

Which has more precedence && or ||?

The logical-AND operator ( && ) has higher precedence than the logical-OR operator ( || ), so q && r is grouped as an operand. Since the logical operators guarantee evaluation of operands from left to right, q && r is evaluated before s-- .

Does Java obey Pemdas?

Yes, Java follows the standard arithmetic order of operations.


4 Answers

No, the way the expression is evaluated goes from left to right, while taking operator precedence into account. So once in a && b the a gets false, b is not evaluated anymore.

JLS §15.23. Conditional-And Operator && says:

The conditional-and operator && is like & (§15.22.2), but evaluates its right-hand operand only if the value of its left-hand operand is true.


Here is a detailed step by step evaluation of how this works:

This is because, when you parse an expression as a human being, you start with the lowest precedence operators first. In this case && has lower precedence then ++.

++a < 0 && foo
        ^^
       start

In order to compute the result of &&, you should know the left operand:

++a < 0 && ++b
^^^^^^^
so compute this

Now, when you want to know the result of ++a < 0, take a look at the lowest precedence operator first, which is <:

++a < 0
    ^
   evaluate this

In order to do that, you will need both left and right operand. So compute them:

++a
0

This is the moment were ++a gets increased.

So, now we are at the bottom. Let's make our way back to the top:

false && foo

And this is where the fact that && is short circuit comes in. Left operand is false, so the right operand expression foo is not evaluated anymore. Which becomes:

false

without the evaluation of the right operand.

like image 186
Martijn Courteaux Avatar answered Sep 27 '22 16:09

Martijn Courteaux


Edit: I missed the point of the question. See revisions for semi-detailed explanation of short-circuit evaluation.

Each operand of the logical-AND and logical-OR operators is a separate expression, and thus, treated independently (given its own order of operators to evaluate, according to correct operator precedence).

So, while ++ has the highest precedence in ++count > 1, that expression is never even evaluated (because of the short-circuiting).

like image 25
Trojan Avatar answered Sep 27 '22 18:09

Trojan


You seem to be dissatisfied with the short circuit evaluation explanation. Why is precedence not important here?

Imagine this code:

if( !(mask > 1) && Increment(count) > 1)

Function application (that is, calling a function by writing the brackets) is the highest precedence, yet the function call will never happen. If short circuit evaluation made allowances for precedence, it wouldn't really work at all.

To expand a little - operators such as ++ , - , etc all map to function calls. However, the compiler needs to understand the order that they bind. This is not the order that they are evaluated in.

So a + b * c doesn't mean workout b * c then the sum. It means only this add( a, multiply(b, c)) The order of evaluation is different in the case of && (though not in my example), to make it easier for programmers to write quick code.

like image 31
user3125280 Avatar answered Sep 27 '22 17:09

user3125280


To avoid confusion, recall that

if (a && b) {
    // do something
}

is semantically the same as:

if (a) {
    if (b) {
         // do something
    }
}

Obviously, if a evaluates to false, the term b will never be seen. In particular, an increment opertor there will not execute.

By recalling this expansion, the behaviour should be easier to understand. It's best to consider && as a shortcut for above nested-if statement. (In the case of having an else statement, you will also need to add two copies of the else code, so it's not as easy.)

A more "exact" representation would be to use a condition method:

boolean condition() {
    if (!a) return false;
    if (!b) return false;
    return true;
}

Again, b will never be evaluated if a returns false already.

like image 44
Has QUIT--Anony-Mousse Avatar answered Sep 27 '22 17:09

Has QUIT--Anony-Mousse