1

During the study of java expression calculation order I faced with one phenomenon I can't explain to myself clearly. There are two quiz questions. It is asked to define the console output.

Example 1

int[] a = {5, 5};
int b = 1;
a[b] = b = 0;
System.out.println(Arrays.toString(a));

Correct console output is: [5,0]

Example 2

public class MainClass {

    static int f1(int i) {
        System.out.print(i + ",");
        return 0;
    }

    public static void main(String[] args) {
        int i = 0;
        i = i++ + f1(i);
        System.out.print(i);
    }
}

Correct console output is: 1,0

As I learned, there is operators groups (levels) with ordered precedence in java and expressions are evaluated according to operator precedence. Also there is associativity of each group and if operators have the same precedence, then they are evaluated in order specified by group associativity. The operators precedence table (from Cay S. Horstmann - Core Java V.1):


    # operator                               associativity
    1 [] . () method call                    left to right
    2 ! ~ ++ -- + - (type) cast new          right to left 
    3 * / %                                  left to right
    4 + -                                    left to right
    ...
    14 = += -=   the rest are omitted        right to left 

With the table above it's become clear that in example 1 the operator with highest priority is array indexing a[b] and then аssignment operators are evaluated from right to left: b=0, then a[1]=0. That is why a=[5,0].

But the example 2 confuses me. According to the precedence table, the operator with highest priority is f1(i) method invocation (which should print 0), then unary post-increment i++ (which uses current i=0 and increments it after), then addition operator 0+0 and аssignment operator finally i=0. So, I supposed the correct output is 0,0.

But in fact it is not. In fact the unary post-increment i++ is calculated first (increasing i to 1), then method invocation f1(i) prints 1 and returns 0 and finally аssignment operator assigns i=0+0, so the final i value is 0 and correct answer is 1,0.

I suppose this is so due to binary addition operator associativity "from left to right", but in this case why do addition is calculated first in example 2, but in example 1 the highest priority operator a[b] is calculated first? I noticed that all operators in example 2 are in different groups, so we shouldn't take operator associativity into consideration at all, should we? Shouldn't we just order all operators from example 2 by precedence and evaluate it in resulting order?

peremeykin
  • 519
  • 5
  • 11

2 Answers2

2

Operator presendence and associativity affect how source code is parsed into an expression tree. But : evaluation order in any expression is still left-to-right.

That's why in i++ + f1(i), we first evaluate i++, then f1(i), and then compute their sum.

Method call having the highest priority means that i++ + f1(i) will never be parsed as (i++ + f1)(i) (if that even makes sense), but always i++ + (f1(i)). Priority does not mean "is evaluated before anything else."

Joni
  • 108,737
  • 14
  • 143
  • 193
2

You are confusing evaluation order with precedence.

The right-to-left associativity of = means that

a[b] = b = 0;

is evaluated as

a[b] = (b = 0);

but the evaluation is still left-to-right, so the value of the first b is evaluated before the value of b is updated.

a[b] = (b = 0)     a = { 5, 5 }, b = 1
// evaluate 'b'
a[1] = (b = 0)     a = { 5, 5 }, b = 1
// evaluate 'b = 0'
a[1] = 0           a = { 5, 5 }, b = 0
// evaluate 'a[1] = 0'
0                  a = { 5, 0 }, b = 0
Andreas
  • 154,647
  • 11
  • 152
  • 247
  • 1
    I post here another link with clearly described differentiation of evaluation order and precedence (if some one else need it): https://introcs.cs.princeton.edu/java/11precedence/ – peremeykin Mar 27 '20 at 19:32