silph silph - 1 month ago 10
Java Question

When are values in Java variables evaluated/returned/fetched in an expression?

According to http://introcs.cs.princeton.edu/java/11precedence/, post-increment operator has higher precedence than addition operator.

So, for the following code:

int i = 1;
int j = i + i++;
System.out.println(j);


I would have thought that the expression assigned to j would have been evaluated as follows (with each line being a "step" in the evaluation) :

i + i++
i + (1) // do post-increment operator; returns 1, and makes i = 2
(2) + (1) // do addition operator. need to get the operand i, so do that.
3


But when I try this program, the value of j is 2.

So I'm confused. In the expression, does it replace all the "i"s in the expression with the current value of i, BEFORE even touching the i++ ?




Edit: the phrase "evaluation order" that people here used, helped me to find the following potentially helpful stackoverflow answer: What are the rules for evaluation order in Java? .




Edit: I made my best guess into an answer below. I still welcome corrections to it.

Answer

Edit: I do not understand the answers others have given completely, but this is my best guess at what is happening. If someone wants to correct this guess, please do so.

My best guess: a + b * c , where a, b, and c are variables, is made into an expression tree, where the operator with lowest precedence is at the top of the tree:

    +
  /   \
 a     *
      / \
     b    c

Now, this tree is evaluated like so: the + operator gets evaluated. To do so, it (recursively) evaluates the left subtree, and its right subtree, then adds these values.

In full, this is what happens:

  - addition operator gets evaluated.
    it says "evaluate my left subtree, then my right subtree,
    then add them together. i return that value"
        - left subtree: is a. evaluate variable a into a value.
          (that is, get the value of variable a.)
        - right subtree: i'm a multiplication operator. to evaluate me,
          evaluate my left subtree, then my right subtree, the nmultiply
          them togeter. i return that value.
                - left subtree: is variable b. evalute that.
                - right subtree: is variable c. evaluate that.

This is why it a finishes its evaluation first, then b, then c, then b * c, then a + (b * c)

In expressions with ++i stuff, the same thing happens. For example, with ++i + i++, the expression tree would look like this:

          +
         / \
    preinc  postinc
       |      |  
       i      i

where (for example) preinc means the preincrement operator (and preincrement operator takes exactly one operand: a variable). the difference here is that when the subtree that has preinc as its root needs to get evaluated, to "evaluate the preinc operator tree" doesn't mean "replace the variable in the operand with the value of the variable" (the way it would for, say, 2 + i ), but instead it means "increment the value in variable i, and then the value of preinc(i) is the new value in the variable i".

in a similar way, the assignment operator = works a little differently than, say, 2 + i.

    int j;
    j = 3;

the expression tree here is

        =
       / \
      j   3

and when a tree with assignment operator as its root needs to get evaluated, this means "the left hand operator must be a variable -- not a value! and then evaluate the right subtree (we expect it to evaluate it to a value), and then put the value in the right subtree in the variable in the left subtree. Now, the value returned by =(j, 3) is the value in the right subtree".

with this guess, I'm able to correctly come up with the answers given for examples in the Java Language Specification on Evaluation Order (link is: https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.7).

that is, if i draw the expression tree, the following two examples are solvable by me:
example:

  int i = 2;
  int j = (i = 3) * i;
  System.out.println(j);

example:

  int b = 9;
  b = b + (b = 3);
  System.out.println(b);