javaoperator-precedenceexpression-evaluation

Differences between Java order of expression, operator precedence and associativity


I came across this question on an exam.

Exam question: What is the result of the following code snippet?

3: var tiger = "Tiger";
4: var lion = "Lion";
5: final var statement = 250 > 338 ? lion : tiger = " is Bigger";
6: System.out.println(statement);

The correct answer was

F. The code will not compile because of line 5

The explanation is:

  1. The code does not compile because the assignment operator has the highest order of precedence in this expression.
  2. Both sides of the ternary operator must have the same type. This expression is invalid, as the left side of the second assignment operator is not a variable, so the answer is option F.
  3. Note that if the question had added explicit parentheses around the expression (Tiger = " is Bigger"), option E would have the correct output.

When I ran the code myself, I got a compilation error:

test.java:11: error: unexpected type
final var statement = 250 > 338 ? lion : tiger = " is Bigger";
                                ^
  required: variable
  found:    value
1 error
error: compilation failed

After asking for second opinions, reading JLS section 15, and these other SO questions:

What are the rules for evaluation order in Java?

If parenthesis has a higher precedence then why is increment operator solved first?

I came up with a few theories:

  1. Order of expression evaluation, operator precedence, and associativity are different concepts.
  2. Expression evaluation respects parentheses and operator precedence, per JLS 15.7.3.
  3. All expression evaluations are made from left to right.
  4. Operator precedence determines grouping of expressions.
  5. Associativity only applies to the same operator and determines the execution order of the expressions using the same operator.
  6. Java checks for valid expressions at compile time, from left to right, respecting parenthesis and operator precedence.
  7. For expressions with operators, it performs this check on the operands in different ways depending on the operator.

With the new knowledge, I will now try to explain why line #5 fail to compile:

  1. Java starts checking for valid expressions, using order of expression evaluation, from left to right.
  2. Java finds the first assignment operator (left-most).
  3. Since assignment operator "=" has Right-To-Left associativity, Java checks if there are any other assignment operator on the right side and start the evaluation of the more-right assignment operator.
  4. It finds one "=", it checks for any other "=" on right side.
  5. I finds no other "=", so it starts to evaluate the operands of this right-most "=".
  6. Per 15.26, Java checks if everything between the previous "=" and this "=" is only a variable.
  7. It finds the expression 250 > 338 ? lion : tiger, which is a valid expression, but this expression evaluates to a value.
  8. Java only allows variable on the left side of the assignment operator, so it fails to compile.

Now I would try to apply this same theory to explain the correct scenario of this code: final var statement = 250 > 338 ? lion : (tiger = " is Bigger");

  1. Java starts checking for valid expressions, using order of expression evaluation, from left to right.
  2. Java does not find any other assignment operator "=" in the same "scope".
  3. Per 15.26, Java checks if the left operand of this "=" is a variable. Passed.
  4. Then it evaluates whether the right operand is a valid expression that returns a value that is assignable to the left operand.

Has the explanation provided by the exam dropped the ball or do I still not understanding how this code did not compile?

  1. They stated that the assignment operator "=" somehow has the highest order of precedence in this expression. Based on this operator precedence table, http://www.cs.bilkent.edu.tr/~guvenir/courses/CS101/op_precedence.html, assignment operator has the lowest precedence.
  2. They used operator precedence interchangeably with order of evaluation expression instead of separating the two concepts?

Solution

  • You are correct, they misspoke, assignment operator has the lowest order of precedence.

    You are incorrect, they never mention "order of evaluation" anywhere (that you've shown, anyway). The code shown doesn't do anything where order of evaluation matters. The assignment has nothing to with order of evaluation.



    1. The code does not compile because the assignment operator has the highest order of precedence in this expression.

    Operator precedence shows:

    9   >   relational
    2   ?:  ternary
    1   =   assignment
    

    Which means that to explicitly show precedence using parenthesis, the statement becomes:

    statement = ((250 > 338) ? lion : tiger) = " is Bigger";
    

    1. Both sides of the ternary operator must have the same type. This expression is invalid, as the left side of the second assignment operator is not a variable, so the answer is option F.

    The ternary operator being ((250 > 338) ? lion : tiger), "both sides" refer to the two assignment operators.

    As it says, "This expression is invalid, as the left side of the second assignment operator is not a variable".


    1. Note that if the question had added explicit parentheses around the expression (Tiger = " is Bigger"), option E would have the correct output.

    You already confirmed that yourself.

    To explicitly show precedence using parenthesis, the statement becomes:

    statement = ( (250 > 338) ? lion : (tiger = " is Bigger") );