Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Execution order of f1() + f2()*f3() expression and operator precedence in JLS

Given an expression f1() + f2()*f3() with 3 method calls, java evaluates (operands of) addition operation first:

int result = f1() + f2()*f3();

f1 working
f2 working
f3 working

I (wrongly) expected f2() to be called first, then f3(), and finally f1(). Because multiplication shall be evaluated before addition.

So, I don't understand JLS here - what am I missing?

15.7.3. Evaluation Respects Parentheses and Precedence

The Java programming language respects the order of evaluation indicated explicitly by parentheses and implicitly by operator precedence.

How exactly operator precedence is respected in this example?

JLS mentions some exceptions in 15.7.5. Evaluation Order for Other Expressions (method invocation expressions (§15.12.4),method reference expressions (§15.13.3)), but I cannot apply any of those exceptions to my example.

I understand that JLS guarantees that operands of a binary operation are evaluated left-to-right. But in my example in order to understand method invocation sequence it is necessary to understand which operation (and both its operands respectively!) is considered first. Am I wrong here - why?

More examples:

int result = f1() + f2()*f3() + f4() + f5()*f6() + (f7()+f8());

proudly produces:

f1 working
f2 working
f3 working
f4 working
f5 working
f6 working
f7 working
f8 working

Which is 100% left-to-right, totally regardless of operator precedence.

int result = f1() + f2() + f3()*f4();

produces:

f1 working
f2 working
f3 working
f4 working

Here the compiler had two options:

  1. f1()+f2() - addition first
  2. f3()*f4() - multiplication first

But the "evaluate-left-to-right rule" works here as a charm!

This link implies that in such examples method calls are always evaluated left-to-right regardless of any parenthesis and associativity rules.

like image 649
Code Complete Avatar asked Aug 14 '19 20:08

Code Complete


2 Answers

You're missing the text immediately under 15.7:

The Java programming language guarantees that the operands of operators appear to be evaluated in a specific evaluation order, namely, from left to right.

The values of the operands of an expression are evaluated before the expression itself. In your specific case, The outermost expression is f1() + [f2() * f3()]. We must first evaluate f1(), then we must evaluate f2() * f3(). Within that, f2() is evaluated first, then f3(), then the multiplication (which returns the value for the operand of the +).

like image 123
chrylis -cautiouslyoptimistic- Avatar answered Oct 28 '22 16:10

chrylis -cautiouslyoptimistic-


JLS §15.17.2. Evaluate Operands before Operation:

The Java programming language guarantees that every operand of an operator (except the conditional operators &&, ||, and ? :) appears to be fully evaluated before any part of
the operation itself is performed.

Thus, f1(), f2() and f3() are evaluated first (left-to-right). Then, operator precedence is applied.

After all, you could observe the execution order in the bytecode, which in my case is:

[...]
INVOKESTATIC Main.f1 ()I
INVOKESTATIC Main.f2 ()I
INVOKESTATIC Main.f3 ()I
IMUL
IADD

Here is how the Expression Tree would look like:

   +
  / \
 /   \
f1    *
     / \
    /   \
   f2   f3

Leaves are evaluated first and the operator precedence is encoded in the tree itself.

like image 34
Oleksandr Pyrohov Avatar answered Oct 28 '22 17:10

Oleksandr Pyrohov