Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does short-circuit evaluation work when operator precedence says it shouldn't?

In JavaScript and Java, the equals operator (== or ===) has a higher precedence than the OR operator (||). Yet both languages (JS, Java) support short-circuiting in if statements:

When we have if(true || anything()), anything() isn't evaluated.

You can also have the following expression: true || foo == getValue()) - for example in an output statement such as console.log(...);, or in an assignment.

Now, according to operator precedence, short-circuiting shouldn't happen, as === = == > || in terms of precedence. (In other words, the comparison should happen first, for which getValue() ought to be called, as the equality check has a higher precedence that the OR comparison.) But it does. getValue() isn't called (as can easily be checked by putting an output statement into its body).

Why (does short circuiting work when the operator precedence says it shouldn't)?
Or am I confusing matters?

like image 256
Christian Avatar asked Sep 30 '17 19:09

Christian


People also ask

How the operator precedence affect the evaluation?

The precedence and associativity of C operators affect the grouping and evaluation of operands in expressions. An operator's precedence is meaningful only if other operators with higher or lower precedence are present. Expressions with higher-precedence operators are evaluated first.

What is the purpose of short-circuit evaluation?

Short-Circuit Evaluation: Short-circuiting is a programming concept in which the compiler skips the execution or evaluation of some sub-expressions in a logical expression. The compiler stops evaluating the further sub-expressions as soon as the value of the expression is determined.

What is the operator precedence rules for expression evaluation?

The operands are always evaluated from left-to-right. The higher-precedence expressions are always evaluated first, and their results are then composed according to the order of operator precedence.

What is short-circuit evaluation in the case of the and operator?

AND(&&) short circuit:If there is an expression with &&(logical AND), and the first operand itself is false, then a short circuit occurs, the further expression is not evaluated, and false is returned.


2 Answers

Or am I confusing matters?

You are. I think it's much simpler to think about precedence as grouping than ordering. It affects the order of evaluation, but only because it changes the grouping.

I don't know about Javascript for sure, but in Java operands are always evaluated in left-to-right order. The fact that == has higher precedence than || just means that

true || foo == getValue()

is evaluated as

true || (foo == getValue())

rather than

(true || foo) == getValue()

If you just think about precedence in that way, and then consider that evaluation is always left-to-right (so the left operand of || is always evaluated before the right operand, for example) then everything's simple - and getValue() is never evaluated due to short-circuiting.

To remove short-circuiting from the equation, consider this example instead:

A + B * C

... where A, B and C could just be variables, or they could be other expressions such as method calls. In Java, this is guaranteed to be evaluated as:

  • Evaluate A (and remember it for later)
  • Evaluate B
  • Evaluate C
  • Multiply the results of evaluating B and C
  • Add the result of evaluating A with the result of the multiplication

Note how even though * has higher precedence than +, A is still evaluated before either B or C. If you want to think of precedence in terms of ordering, note how the multiplication still happens before the addition - but it still fulfills the left-to-right evaluation order too.

like image 195
Jon Skeet Avatar answered Sep 20 '22 05:09

Jon Skeet


According to the language specification, https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.24

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 true, the value of the conditional-or expression is true and the right-hand operand expression is not evaluated.

So if you have a || b==c, it is not interpreted as (a || b) == c, because || has lower precedence, as you found in the tutorial. Instead, it is interpreted as a || (b==c). Now since a is the left side of ||, it is evaluated first.

like image 38
Chloe Avatar answered Sep 18 '22 05:09

Chloe