Why is this Java operator precedence being ignored here?
Asked Answered
L

7

5

The following code prints out "3", not "4" as you might expect.

public class Foo2 {
    public static void main(String[] args) {
        int a=1, b=2;             
        a = b + a++;
        System.out.println(a);
    } 
}

I understand how. The postfix increment happens after the value of "a" has been loaded. (See below).

What I don't quite understand is the why. The operator precedence of postfix ++ is higher than + so shouldn't it execute first?

% javap -c Foo2

Compiled from "Foo2.java"
public class Foo2 extends java.lang.Object{
public Foo2();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

public static void main(java.lang.String[]);
  Code:
   0:   iconst_1
   1:   istore_1
   2:   iconst_2
   3:   istore_2
   4:   iload_2
   5:   iload_1
   6:   iinc    1, 1
   9:   iadd
   10:  istore_1
   11:  getstatic       #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   14:  iload_1
   15:  invokevirtual   #3; //Method java/io/PrintStream.println:(I)V
   18:  return
Laurencelaurene answered 28/9, 2009 at 21:33 Comment(0)
T
20

Postfix ++ increments the value of variable, and returns the value that was there before the increment. Thus, the return value of operator++ in your example will be 1, and of course 1 + 2 will give 3, which is then assigned to a. By the time of assignment, ++ has already incremented the value of a to 2 (because of precedence), so = overwrites that incremented value.

Treasonous answered 28/9, 2009 at 21:35 Comment(1)
Best explanation I have seen for the precedent topic.Balkin
M
13

Operator precedence is not being ignored here.

The only slightly confusing thing about a++ is that the postfix ++ operator has two distinct effects:

  1. it increases the variable it's applied to by one
  2. it has a return value that is equal to the value of the variable before it is increased

So if a has the 1 and b has the value 2 before this line:

a = b + a++;

Then the following steps happen:

  • evaluate b
    • the expression b has the value 2, so remember the value 2
  • evaluate a++
    • the expression a++ has the value 1, so remember the value 1
    • increment the value in variable a by one, so it now holds the value 2
  • add the results of the two expressions (which are 2 and 1 respectively)
  • 2 + 1 = 3
  • assign 3 to the variable a

As you see, the code effectively assigns two values to a:

  • 2 is assigned to a during the evaluation of a++
  • 3 is assigned to a as a result of the assignment

Since the second assignment happens after the first one, you only see the effect of the second one and you will always observe a as having the value 3 after that line.

Edit: I'll try to provide an interpretation of the decompiled code. It might be a bit hard to follow, unless you know how the JVM works internally (i.e. you know how that the JVM is a stack-based VM and what that means):

   // Push the constant 1 on the stack
   0:   iconst_1
   // Pop the topmost value from the stack (1) and store it in the local variable #1 (a.k.a "a")
   1:   istore_1
   // Push the constant 2 on the stack
   2:   iconst_2
   // Pop the topmost value from the stack (2) and store it in the local variable #2 (a.k.a "b")
   3:   istore_2
   // Load the local variable #2 ("b") and push its value (2) on the stack
   4:   iload_2
   // Load the local variable #1 ("a") and push its value (1) on the stack
   5:   iload_1
   // Increment the local variable #1 by 1 (this action does not use the stack!)
   6:   iinc    1, 1
   // Pop the 2 topmost values from the stack (2 and 1), add them and push the result (3) back on the stack
   9:   iadd
   // Pop the topmost value from the stack (3) and store it in local variable #1 ("a")
   10:  istore_1

Lines 0-3 simply implement

int a=1, b=2;

The lines 4-10 implement

a = b + a++;

I've left out the other lines, as nothing interesting happens there anymore.

As an interesting sidenote: it's plainly visible that this code is not optimized at all. The reason for this is that optimization is the task of the runtime environment (i.e. the JVM) in the Java world and not of the compiler (javac for example).

Myosin answered 28/9, 2009 at 21:40 Comment(0)
K
3

The postincrement/decrement operator (a++) returns the value before the increment. The preincrement/decrement (++a) returns the value after the increment.

Kelliekellina answered 28/9, 2009 at 21:58 Comment(0)
H
2

I had the same problem with this operator precedence definition (as defined here) and I think none of the above replies are exactly explaining and clarifying the paradox in this definition. This is what I think the higher precedence of postfix operator to other operators (in this example to binary plus operator) means.

Consider the following code fragments:

    int x = 1, y =4 , z;
    z = x+++y;  // evaluates as: x++ + y
    System.out.println("z : " + z); // z: 5
    System.out.println("y : " + y); // y: 4
    System.out.println("x : " + x); // x: 2

    x = 1; y =4 ; 
    z = x + ++y;
    System.out.println("z : " + z); // z: 6
    System.out.println("y : " + y); // y: 5
    System.out.println("x : " + x); // x: 1

As you can see, a single expression z = x+++y; which has two possible evaluations, will be evaluated as z = x++ + y; by java compiler. This means that from three plus sign which came together, compiler assumes the first two of them as a postfix operator and the third one as a binary plus operator. This is in fact a result of higher precedence of postfix operator over other operators.

The second code fragment shows how the outputs differ by writing the expression as z = x + ++y; which explicitly specifies which plus sign is a binary operator.

Hodosh answered 22/2, 2014 at 20:45 Comment(0)
R
1

This isn't a matter of precedence, it's a matter of the definition of the operator. By definition the postfix operator executes after the variable is used in the enclosing expression.

Rah answered 28/9, 2009 at 21:35 Comment(0)
C
0

what the postfix ++ operator is saying is:

Use the original value of the variable in whatever equation, and then increment the variable afterwards.

Cully answered 28/9, 2009 at 21:37 Comment(0)
A
0

I have never seen

 a = b + a++; 

being used, it strikes me as bad coding. Using it like that would i think also mean that you could write:

int a++ = 1;

which doesn't work.

normally you would see

int a = 1;
int b = 2;
a = b + a; // 3

a = 1;
a++;
a = b + a; // 4
Andonis answered 27/11, 2013 at 14:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.