0

So everywhere I look, it says that && is evaluated first, then || is evaluated second. So either I am doing something wrong or it is wrong. Here's the code:

static boolean foo(boolean b, int id){ System.out.println(id); return b;}

static{ System.out.println(foo(true, 3) && foo(true, 1) || foo(false, 2)) }
//returns 3 1

static{ System.out.println(foo(true, 2) || foo(true, 3) && foo(true, 1)} 
//returns 2

In the first static block, && goes first, short circuits and ignores the || but in the second static block which is simply the reverse, || goes first and ignored the &&. This demonstrates left to right but according to the java doc, && has higher precedence which means && should always go first.

Some documents about precedence (logical and is higher than or):
1. https://docs.oracle.com/javase/tutorial/java/nutsandbolts/operators.html
2. https://chortle.ccsu.edu/Java5/Notes/chap40/ch40_16.html
3. http://www.cs.bilkent.edu.tr/~guvenir/courses/CS101/op_precedence.html
...

Bai Yang
  • 394
  • 2
  • 5
  • 17
gmanrocks
  • 261
  • 3
  • 12
  • 2
    It's evaluated left to right... not sure where you are looking. – Elliott Frisch Mar 13 '19 at 05:04
  • @ElliottFrisch sorry I forgot the second static. I reversed the && and || and it evaluated || first as if it is left to right. – gmanrocks Mar 13 '19 at 05:08
  • 1
    I think what's happening is that the logic is being short-circuited. It's normal when evaluating `||` that once a `true` is obtained, then the rest of the expression doesn't need to be evaluated, because it's already `true`. Let us know if you were thinking something different. – markspace Mar 13 '19 at 05:30
  • Some more info here: https://stackoverflow.com/questions/8759868/java-logical-operator-short-circuiting – markspace Mar 13 '19 at 05:31
  • And also here: https://en.wikipedia.org/wiki/Short-circuit_evaluation – markspace Mar 13 '19 at 05:31
  • @markspace yeah it would short circuit if the precedence or || is higher then &&… but since || is less than && it should look at && next regardless of the short circuit. Doesn't that only occur when the || is to actually be evaluated. – gmanrocks Mar 13 '19 at 05:32
  • 1
    No I don't think that's correct. Even if && is higher, it's still true that as long as the left side of || is true, then the whole expression is true. In some ways I think you have it backwards. Because && has higher precedence, that means || goes last and then controls the final outcome. Work it out with a truth table and see if I'm correct. – markspace Mar 13 '19 at 05:36
  • 1
    P. S. And remember, short-circuit evaluation requires that the left side be evaluated first, so that's what the || and && are doing. That's why you get two outputs for the first one and only one for the second. – markspace Mar 13 '19 at 05:37
  • @markspace higher precedence does mean going first. In the table */ has higher precedence than +- so that is not backwards. However, ill look into this weird short circuiting enigma. Maybe it is smart enough to just skip the rest regardless of precedence. – gmanrocks Mar 13 '19 at 05:38
  • Logical boolean expressions don't work exactly the same way as multiplication and addition. Basically, yes, the optimizer can determine that parts of the expression can be skipped, and short circuit requires that they are skipped. So it's just part of the spec. – markspace Mar 13 '19 at 05:40
  • 1
    Too much confusion here. 1. The *operands* are evaluated left to right. 2. The *operators* are evaluated according to precedence. 3. The RHS of `&&` isn't evaluated if the LHS is false. 4. The RHS of `||` isn't evaluated if the LHS is true. – user207421 Mar 13 '19 at 09:04
  • @markspace It is the defined behaviour of these operators in the JLS. It has nothing to do with 'the optimizer' whatsoever. – user207421 Mar 13 '19 at 09:13
  • @ElliottFrisch https://docs.oracle.com/javase/tutorial/java/nutsandbolts/operators.html – Bai Yang Jan 29 '20 at 03:08
  • Here is a good answer: https://stackoverflow.com/questions/23620919/why-does-the-or-go-before-the-and – Bai Yang Jan 29 '20 at 03:44
  • Also here: https://stackoverflow.com/questions/24602875/logical-and-and-logical-or-operator-precedence – Bai Yang Jan 29 '20 at 03:52

1 Answers1

0

Higher predecence of && just means that

foo(true, 2) || foo(true, 3) && foo(true, 1)

is the same as

foo(true, 2) || (foo(true, 3) && foo(true, 1))

but not

(foo(true, 2) || foo(true, 3)) && foo(true, 1)

Nothing else. It doesn't imply anything about evaluation order.

Now, for most operators, evaluating x op y requires evaluating both x and y. If || was one of them, it would be the same as (return is from evaluating ||, not from the entire method)

boolean tmp1 = foo(true, 2);
boolean tmp2 = foo(true, 3) && foo(true, 1);
return tmp1 || tmp2;

and && would indeed "go first". But there are three operators which don't work like that: &&, || and ?:. Instead you get

boolean tmp1 = foo(true, 2);
if (tmp1) {
    return true; 
} else {
    return foo(true, 3) && foo(true, 1);
}
Alexey Romanov
  • 167,066
  • 35
  • 309
  • 487
  • I understand the point of short-circuiting. It does not evaluate the right side if it can guarantee the complete evaluation is true. But foo(true, 2) || (foo(true, 3) && foo(true, 1)) -> && first because it has more parenthesis right? For example: a + (b + (c + d)) where (a, b, c, d) = (1, 2, 3, 4) -> 1 + (2 + (3 + 4)) -> 1 + (2 + 7) -> 1 + 9 -> 10 – gmanrocks Mar 13 '19 at 13:55
  • Can you give me an example where || then && left to right does && first? – gmanrocks Mar 13 '19 at 13:58
  • "But foo(true, 2) || (foo(true, 3) && foo(true, 1)) -> && first because it has more parenthesis right? For example: a + (b + (c + d))" No. Left-hand side `foo(true, 2)` first, then `foo(true, 3) && foo(true, 1)` _if necessary_ (and it isn't). If `||` and `&&` didn't short-circuit, the order would be: 1. `foo(true, 2)`; 2. `foo(true, 3)`; 3. `foo(true, 1)`; 4. `&&`; 5. `||`. But they do. – Alexey Romanov Mar 13 '19 at 14:23
  • "Can you give me an example where || then && left to right does && first?" Just change `true`s to `false`. But even then: 1. `foo(false, 2)` gets executed first, before `&&`. 2. you could say `&&` is evaluated inside `||`, not before it. But it finishes before `||` does. – Alexey Romanov Mar 13 '19 at 14:29
  • That does not execute && first. It returns 2 3 1 where 2 is on the left of or. That still executes || first. – gmanrocks Mar 13 '19 at 18:27
  • Then `a() + b() * c()` doesn't execute `*` first, because it'll start with `a()` (just like `a() || b() && c()`). – Alexey Romanov Mar 13 '19 at 18:34
  • foo(false, 2) || foo(true, 3) && foo(true, 1) -> 2 3 1 tested still does || first – gmanrocks Mar 13 '19 at 18:41
  • 1
    I really don't know how to explain it any simpler. What you are checking is that it evaluates the left-hand side of `||` first. But the same will happen for any operators at all, whatever their precedence is (and whether they short-circuit or not). But `&&` _finishes_ before `||` does (in this example). – Alexey Romanov Mar 13 '19 at 18:54