0
class Hello {
    public static void main(String args[]) {
        int i = 10;
        i *= i++ + i;
        System.out.println(i);
    }
}

According to operator precedence, the postfix operator has more precedence than the multiplication operator. The operands inside parentheses have more precedence.

Evaluating them first: i*(i++ + i) So, now, it is 10+11 inside the parentheses: i*(21)

The current value of i is 11

Secondly, evaluating the multiplication operator due to the next precedence, should it not be 11*21=231?

Though, I know the answer is 210, why is the logic I explained above wrong?

takendarkk
  • 3,347
  • 8
  • 25
  • 37
pravi
  • 19
  • 3
  • `The current value of i is 11` - what makes you say that? – Mat Jul 24 '17 at 14:39
  • @Mat - OP says that because after the increment of `i` its value is indeed 11, and the incorrect assumption is that this happens before any of the other `i` operands is evaluated – Mark Adelsberger Jul 24 '17 at 14:50

4 Answers4

5

Split it up into the following

i = i * (i++ + i);

Now, you have:

i = 10 * (i++ + i);

Then, you have:

i = 10 * (10 + i);

Then, you have:

i = 10 * (10 + 11);

Then, you have:

i = 10 * (21);

Then, you have:

i = 210;

As you can see, the value of "i" is first loaded, then the remaining of the calculation is done, not the other way around.

EDIT: Somewhere in between, the value of i is also set to 11, hence the number "11" at step 4, but after that, it gets overwritten at the end so this value doesnt matter any more.

Swapping the calculation will result in what you want:

i = (i++ + i) * i;
Wietlol
  • 1,001
  • 1
  • 10
  • 25
1

First thing to notice here is that you're not doing a simple multiplication, you're using a compound assignment operator, that is an operator that encapsulates performing an operation on a variable and then assigning the result to the original variable.

From the JLS section about compound assignment operators (like *=):

  • First, the left-hand operand is evaluated to produce a variable. If this evaluation completes abruptly, then the assignment expression completes abruptly for the same reason; the right-hand operand is not evaluated and no assignment occurs.

  • Otherwise, the value of the left-hand operand is saved and then the right-hand operand is evaluated. If this evaluation completes abruptly, then the assignment expression completes abruptly for the same reason and no assignment occurs.

  • Otherwise, the saved value of the left-hand variable and the value of the right-hand operand are used to perform the binary operation indicated by the compound assignment operator. If this operation completes abruptly, then the assignment expression completes abruptly for the same reason and no assignment occurs.

The highlighted text guarantees that on the left hand side of the multiplication the original value of i will be used, that is 10. (And the right hand side evaluates to 21, as you correctly derived already.)

The other, arguably more important lesson is that operator precedence is not the same as evaluation order. Precedence is only used to parse the expression into an expression tree but operators are always evaluated from left to right, and from the outside in.

In your case the expression tree looks roughly like this (note how the lowest precedence operator ends up at the root of the tree):

    *=
   /  \
  i    +
      / \
     i++ i

...and now it is evaluated from the top to bottom, left-to-right like this:

    *=         *=         *=          *=       210
   /  \       /  \       /  \        /  \
  10   +  -> 10   +  -> 10   +   -> 10   21 ->
      / \        / \        / \
     i++ i      10  i      10  11
biziclop
  • 48,926
  • 12
  • 77
  • 104
  • I'd say that's *not* the important thing, since the result would be the same if the expression were `i = i * (i++ + i)` – Mark Adelsberger Jul 24 '17 at 14:52
  • @MarkAdelsberger That's an entirely fair point, but OP kept referring to it as the multiplication operator, which it isn't. I've edited my answer to point out the other, arguably more important mistake. – biziclop Jul 24 '17 at 14:54
0

Just because operators must be applied in a particular order, does not mean that the direct operands of the highest-precedence operator always have to be evaluated first.

In fact, the rule that applies here is:

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 left-hand operand of a binary operator appears to be fully evaluated before any part of the right-hand operand is evaluated.Jul 23, 2011

This can be very confusing, unless you follow a simple rule: Don't embed sub-expressions whose side-effects will affect the operands mid-calculation, because it makes your code unreadable.

Mark Adelsberger
  • 42,148
  • 4
  • 35
  • 52
0
int i = 10;

i *= i++ + i;
i = i * (i++ +i)
  • i++ will increment the value of i, but return the original value that i held before being incremented.

    i = 10;
    j = i++;
    (i is 11, j is 10)
    
  • So, you have:

    i = 10 * (10 + 11);
    i = 10 * (21)
    i = 210
    
  • So, your answer is : 210.

Md. Rezwanul Haque
  • 2,882
  • 7
  • 28
  • 45
  • Yes, but that doesn't capture the reasoning error that OP made. (I assumed it would too, at first, but on closer read, that part was correct.) – Mark Adelsberger Jul 24 '17 at 14:56