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:
- The code does not compile because the assignment operator has the highest order of precedence in this expression.
- 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.
- 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:
- Order of expression evaluation, operator precedence, and associativity are different concepts.
- Expression evaluation respects parentheses and operator precedence, per JLS 15.7.3.
- All expression evaluations are made from left to right.
- Operator precedence determines grouping of expressions.
- Associativity only applies to the same operator and determines the execution order of the expressions using the same operator.
- Java checks for valid expressions at compile time, from left to right, respecting parenthesis and operator precedence.
- 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:
- Java starts checking for valid expressions, using order of expression evaluation, from left to right.
- Java finds the first assignment operator (left-most).
- 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.
- It finds one "=", it checks for any other "=" on right side.
- I finds no other "=", so it starts to evaluate the operands of this right-most "=".
- Per 15.26, Java checks if everything between the previous "=" and this "=" is only a variable.
- It finds the expression
250 > 338 ? lion : tiger
, which is a valid expression, but this expression evaluates to a value. - 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");
- Java starts checking for valid expressions, using order of expression evaluation, from left to right.
- Java does not find any other assignment operator "=" in the same "scope".
- Per 15.26, Java checks if the left operand of this "=" is a variable. Passed.
- 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?
- 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.
- They used operator precedence interchangeably with order of evaluation expression instead of separating the two concepts?