Summary
Under JDK-8294461, CSR JDK-8296148, javac handling of effectively final variables have been adjusted to follow the existing specification wording. It is, however, necessary to re-evaluate the specification in the light of newly filled JDK-8299416, so the proposal is to revert the javac changes done under JDK-8294461.
Problem
javac was not implementing the handling of effectively final variables exactly per the JLS wording, which was fixed under JDK-8294461. However, the current specification handling for effectively final and blank final variables differs slightly, leading to suspicious side-effects. More time is needed to re-evaluate the handling of effectively final variables in the JLS and then consequently in javac.
Specifically, variables may, in some cases, be both definitely assigned and unassigned at the same time. This may happen for example for constant expressions:
JLS 16.1.1.:
V is [un]assigned after any constant expression whose value is false when true.
Or after a break statement (which was the case in JDK-8294461:
JLS 16.2.13.:
By convention, we say that V is [un]assigned after any break, yield, continue, return, or throw statement
For assignments to blank final variables, this is not an issue, as the assertion for assignment to blank final variables does not speak about definite assignment, only definite unassignment:
JLS 16:
For every assignment to a blank final variable, the variable must be definitely unassigned before the assignment, or a compile-time error occurs.
Contrary to that, for effectively final variables, both definite assignment and unassignment are considered:
JLS 4.12.4.:
A local variable declared by a statement and whose declarator lacks an initializer is effectively final if all of the following are true:
...
Whenever it occurs as the left hand side in an assignment expression, it is definitely unassigned and not definitely assigned before the assignment; that is, it is definitely unassigned and not definitely assigned after the right hand side of the assignment expression (ยง16 (Definite Assignment)).
...
Up to JDK-8294461, javac was not implementing the "not definitely assigned" condition for effectively final. This was fixed under JDK-8294461. In combination with variables that are both definitely assigned and unassigned at the same time, it leads to surprising side-effects like:
int i; //note the variable can be marked final
if (false) {
/* this assignment makes the variable not effectively final, as "i" is definitely assigned and unassigned at
* the point when the assignment happens
*/
i = 0;
} else {
i = 1;
}
Even though the JDK-8294461's CSR, JDK-8296148, talks specifically about the increment or decrement operators, the javac change actually implements the check described above.
Solution
The change for JDK-8294461 will be reverted. The javac behavior regarding effectively final variables will revert back to the state where it ignored the "not definitely assigned" condition in the JLS, which matches the pre-existing behavior in JDK 19 and older.
The handling of effectively final and final variables in JLS will be re-evaluated separately, with further changes being done as needed.
Specification
javac will no longer implement the "not definitely assigned" condition of JLS 4.12.4 when determining effectively final variables.
- csr of
-
JDK-8299849 Revert JDK-8294461: wrong effectively final determination by javac
-
- Closed
-
- relates to
-
JDK-8296148 wrong effectively final determination by javac
-
- Closed
-