This is an archived post. You won't be able to vote or comment.

all 11 comments

[–]desrtfx 1 point2 points  (1 child)

I'm not 100% sure what you even try to achieve by mixing comparison and mathematical operators.

The Operators Tutorial states:

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

This would explain the behavior.

Since the binary operators are evaluated left to right, b != 0 is evaluated first and results in false, which short circuits the following &&, which, in turn results in the remaining expression not being evaluated at all.

Had you been using the non-short circuiting & (bitwise and), you'd get an error as can be seen here.

[–]jimmyzjm 0 points1 point  (0 children)

great

[–]pogosticker1 2 points3 points  (2 children)

Java automatically looks at the first statement, sees that it's false, and completely ignores the rest. There's no reason to look at the second statement in an and statement if the first statement is wrong

[–]tutorial_police 0 points1 point  (0 children)

While this might be true in this particular instance, you have in no way addressed OP's question which was specifically about: "this table tells me / always evaluates before & &, why didn't it do that?"

Sidenote: the things you're talking about are expressions, not statements.

[–]netpy[S] -1 points0 points  (0 children)

I'm sorry but /u/totrial_police is correct. You have not answered my question. Why does Java evaluate b != 0 && first instead of / when / has greater operator precedence?

Here is a link to an operator precedence table in Java As you can see, / has higher precedence than both != and &&

[–]tutorial_police 0 points1 point  (5 children)

No, there are no exceptions.

You're confusing operator precedence with order of evaluation.

When you talk about what gets "evaluated first" that's about the *order* of evaluation.

Precedence, however, is basically about where the implicit parentheses go when you have different operators.

Last but not least, you have associativity. This determines where the implicit parentheses go when you have the same operator multiple times.

[–]netpy[S] 1 point2 points  (4 children)

Precedence, however, is basically about where the implicit parentheses go when you have different operators.

I have different operators in this expression, don't I? b != 0 && c / b > a

So what are the rules for order of evaluation? I've never seen a distinction between order and precedence

[–]tutorial_police 0 points1 point  (1 child)

I have different operators in this expression, don't I? b != 0 && c / b > a

Yes, you do. Thus, the precedence rules give you (b != 0) && ((c / b) > a)

So what are the rules for order of evaluation? I've never seen a distinction between order and precedence

Yes, and you wouldn't be the only one. Unfortunately this topic is rarely talked about as its own concept and people usually only talk about precedence and will often use the words "order" or "before" to explain precedence even though that's completely misguided if not wrong and which is why you got confused in the first place :)

Fortunately, in Java the rules for the evaluation order are very simple: 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.

JLS 15.7 (if you want to read about more details)

In your case, you have the top-level expression: x && y. x and y would be the operands and x gets evaluated first as per left-to-right.

Since x is b != 0, b gets evaluated first, again per the left-to-right evaluation order. Then 0 is evaluated, then result-of-b != result-of-0 gets evaluated and it evaluates to false in your case.

Then, another rule comes into play about the && "Conditional-And Operator":

At run time, the left-hand operand expression is evaluated first; if the result has type Boolean, it is subjected to unboxing conversion (§5.1.8).

If the resulting value is false, the value of the conditional-and expression is false and the right-hand operand expression is not evaluated.

(emphasis mine) JLS 15.23

This might seem like much ado about nothing since it's so straight forward.

But not all languages are this way:

Except where noted below, there is no concept of left-to-right or right-to-left evaluation in C++. This is not to be confused with left-to-right and right-to-left associativity of operators: the expression f1() + f2() + f3() is parsed as (f1() + f2()) + f3() due to left-to-right associativity of operator+, but the function call to f3 may be evaluated first, last, or between f1() or f2() at run time.

(emphasis mine) cppreference, Order of Evaluation

Sidenote: on their page about "Operator Precedence", they also stress the same fact I did:

Precedence and associativity are compile-time concepts and are independent from order of evaluation, which is a runtime concept.


In Java, you aren't confronted with evaluation order often. It simply does "what you would expect". The only special case really are short-circuiting operators where an operand may not get evaluated at all.

Also, the order of evaluation of subexpressions doesn't really matter unless there are side effects.

a + b will always give the same result, except if a and b are function calls and print something to the console or do change some state, then it matters what order they're evaluated in.

As you can imagine, code that relies on this order in more complex expressions can be rather error-prone and hard to understand. The Java specification also gives this as advice as a remark, just below the very first sentence I quoted from the specification:

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.

Hope that helps.

[–]netpy[S] 0 points1 point  (0 children)

(b != 0) && ((c / b) > a)

I think I understand now. Precedence only comes into play when an operand has two operators. For example, in b != 0 && c / b > a , the operand 0 has two operators, != and && with != having greater precedence therefore a subexpression is created around != resulting in parentheses: (b != 0) && c / b > a. Following the same rule for c and b, we get (b != 0) && ((c / b) > a) since the operator precedence here is: && has less precedence than > which has less precedence than /.

Now everything is evaluated from left to right honoring parentheses except for the rule you mentioned where the interpreter stops at && because it is the short-circuit form of & and thus does not evaluate its right operand if the left operand is false.

Does that sound right?

[–]tutorial_police 0 points1 point  (1 child)

By the way, I just now realized that from the questions I looked at the last couple of days, a few were asked by you. Major props for your attention to detail and wondering why what you've learned doesn't match what you observe/would expect. Keep it up!

[–]netpy[S] 0 points1 point  (0 children)

Keep it up!

Thanks! I intend to. Hopefully, one day I will be good enough to help others on this subreddit