JDK-8300691 - final variables in for loop headers should accept updates

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Wed Oct 16 13:56:19 UTC 2024


Hi Archie,
there were several interesting design discussions on the JEP [1] you 
have created for this.

An intersting angle we discussed was whether we feel imperative for 
loops are special enough to deserve special treatment, or whether this 
is the start of a loosening process that will eventually lead to allow 
capture for every local variable /value/.

In order to better characterize the nature of the problem we’re dealing 
with, it would be great if we could gather some more evidence on how 
many “dummy” local variables are introduced for the sole purpose of 
being able to capture them in a lambda/inner class. More precisely, a 
“dummy” local variable is a local variable that:

  * is initialized with the value of some other local variable
      o is only referenced inside a capture context (either lambda or
        inner class)

(corollary: all “dummy” local variables are effectively-final).

Example:

|int x = ... ... x = ... // reassignment ... int x2 = x; // x2 is 
effectively-final ... () -> x2; // x2 is only used here! |

Could you come up with a javac patch that detects such “dummy” variable 
declarations and prints a note/warning in the compiler output?

Then we can try to run the modified javac to build the JDK and see how 
many warnings are found there. Similarly, we can try the modified 
compiler against Maven artifacts (we have some infrastructure to do 
that), or against other interesting codebases (perhaps Liam, cc’ed, 
might help here?)

Let me know what you think.

Cheers
Maurizio

[1] - https://git.openjdk.org/jdk/pull/21415

On 11/09/2024 00:23, Archie Cobbs wrote:

> I'm curious about this possible future language tweak and have been 
> looking at it more closely: https://bugs.openjdk.org/browse/JDK-8300691
>
> I think this would be a nice practical change that fits well within 
> the Amber ambit. However, I'm stuck on one question.
>
> To summarize, there are two independent changes being proposed:
>
>  1. Prevent statements in for() loop steps from causing for() loop
>     variables to lose their "effectively final" status
>  2. Allow final for() loop variables to be mutated in the for() step
>     (but not the for() body)
>
> Change #1 would allow code like this:
>
> for (int i = 0; i < 10; i++) {
>     Runnable r = () -> System.out.println(i);   // hooray, "i" is 
> effectively final
> }
>
> Change #2 would allow code like this:
>
> for (final int i = 0; i < 10; i++) {
> System.out.println(i);          // we can rest assured "i" can't 
> change in here
> }
>
> Change #1 is straightforward but Change #2 raises an issue. A final 
> initialized variable is not only immutable but also can be a constant 
> expression, and this affects reachability analysis.
>
> For example, these two examples do not compile:
>
> final int x = 0;
> while (x != 0)
> System.out.println(x);         // error: unreachable statement
> System.out.println("done");
>
> final int x = 0;
> while (x == 0)
> System.out.println(x);
> System.out.println("done"); // error: unreachable statement
>
> We shouldn't expect the equivalent for() statements to compile either, 
> and in fact today they don't:
>
> for (final int x = 0; x != 0; )
>     System.out.println(x);         // error: unreachable statement
> System.out.println("done");
>
> for (final int x = 0; x == 0; )
>     System.out.println(x);
> System.out.println("done");        // error: unreachable statement
>
> But now suppose we add a step, which Change #2 would newly allow:
>
> for (final int x = 0; x != 0; x++)
>     System.out.println(x);         // error: unreachable statement... ?
> System.out.println("done");
>
> for (final int x = 0; x == 0; x++)
>     System.out.println(x);
> System.out.println("done");        // NOT an unreachable statement
>
> In the first example, the inner statement is still unreachable, so 
> it's OK for the compiler to still report that error, but in the second 
> example, the final statement is now obviously reachable, so the 
> compiler must  do something different. Moreover it would be doing 
> something different based on inspection of the step for mutations to 
> "x", which seems like "spooky action at a distance" and could be 
> spec-challenging.
>
> Alternatively, the compiler could change its behavior to never 
> consider final loop variables as constant expressions, but this could 
> break existing code.
>
> Of course, if Change #2 had too many issues, Change #1 would still be 
> useful on its own.
>
> Thoughts?
>
> Thanks,
> -Archie
>
> -- 
> Archie L. Cobbs

​
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-dev/attachments/20241016/34b333fe/attachment-0001.htm>


More information about the amber-dev mailing list