JDK-8300691 - final variables in for loop headers should accept updates
Remi Forax
forax at univ-mlv.fr
Wed Oct 23 21:49:04 UTC 2024
> From: "Maurizio Cimadamore" <maurizio.cimadamore at oracle.com>
> To: "John Rose" <john.r.rose at oracle.com>
> Cc: "Archie Cobbs" <archie.cobbs at gmail.com>, "amber-dev"
> <amber-dev at openjdk.org>, "Liam Miller-Cushon" <cushon at google.com>
> Sent: Wednesday, October 23, 2024 10:55:20 PM
> Subject: Re: JDK-8300691 - final variables in for loop headers should accept
> updates
>>> …
>>> Of course you can argue it both ways: by making the new capture treatment only
>>> available for induction variables in for loops (where the variable is not
>>> mutated in the body) we do reduce (not eliminate!) the chances of somebody
>>> observing different values for the same induction variable.
>> I don’t see the sub-point about “not eliminate”; I think the reduction is
>> complete to the point of elimination, because of the special (weird) properties
>> of the old-for loop.
> Well, there's no sub-point - I'm merely stating the (perhaos obvious?) fact that
> if you allow to capture induction variable you can set up a contrived example
> where you execute a lambda which captures the _previous_ version of the
> induction variable. That said, the same thing happens in for-each loops - so
> we're back to the subjective judgment of whether it's ok for counted loop to
> have same rules of for-each loops despite a more explicit mutation (even if
> controlled).
>> I also think the feature will be enjoyed far more than “20 or 30” times, or
>> whatever corpus analysis tells us. Corpus analysis by definition measures the
>> way people have used the language in the past, and that is often affected by
>> their avoidance of sharp corners in the language. I believe this little polish
>> of a central syntax in Java will affect the way people shape their code in the
>> future. At least, it will for me, because I know I’ve done extra work to avoid
>> the sharp corner in the past.
> Here I don't think I agree. It's not like developers are avoiding loop because
> the capture rules are what they are. If you need a loop, you need a loop. Maybe
> they are avoiding capturing lambdas - but again, replaced with what? Anonymous
> inner classes will have similar issues. And if you need capture you need
> capture - you can't make that go away. Perhaps they are disguising the capture
> a little harder, by using an array, or an AtomicXYZ. But I'd say that, while
> the numbers we have seen might surely underestimate things a bit, I don't
> expect to see dramatic differences in the wild.
> There's another reason I think this is the case - since Java 8 there are often
> better ways to write loops: using the Stream API. Of course not every loop can
> be rewritten using streams, but a lot can, and developers have already done so
> - perhaps lowering the number of legacy loops (of all kinds) requiring some
> kind of capture.
As a teacher, here is the issue most of my student struggle with, they have a code like
for(var i = 0; i < 4; i++) {
new Thread(() -> {
...
}).start(),
}
The code can use plain threads, virtual threads, an executor or structured concurrency, etc ... you get the idea.
Then they want to access to induction variable 'i' inside the lambda.
At that point, some students knows how to fix the issue using another local variable in the body of the loop but others start to become "creative",
- some are using IntStream.range().forEach(i -> ) but usually, it fails because it's quite usual for this kind of code to have also a method call that throws a checked exception (Thread.sleep(), object.wait(), thread.join(), future.get(), etc)
- some try to write their own range() method using an "enhanced for" like Tagir said, here are the usual examples
- for(var i : List.of(0, 1, 2, 3)) {
- for(var i : IntStream.range(0, 4).boxed().toList()) {
- for(var i : new int[] { 0, 1, 2, 3 }) {
- for(var i : (Iterable<Integer>) IntStream.range(0, 4)::iterator) { // those students have read Effective Java
For me, allowing my students to capture the induction variable of simple for loops so they can focus on the rest of the code is a win.
> Maurizio
Rémi
>> — John
>> P.S. Archie, I don’t think character positions should be appealed to; that’s not
>> a natural tactic for the JLS. (Despite some very low-level and odd rules about
>> forward references between field initializers, which sort of depend on
>> character positions.) Appealing to character positions instead of block
>> structure inhibits understanding of code at the AST level (which IDEs want to
>> do). If I were going in that direction I’d piggy-back on the reachability
>> analysis the JLS already has, in order to track setting of finals. I’d ask,
>> “can the captured variable be reassigned in some code B reachable from the
>> capture point A?” in a way analogous to asking “can this final, once assigned
>> at point A, ever be reassigned at point B?” Note the connection to finals,
>> which is not accidental. Finals are all about saying, “this variable is only a
>> value, and does not provide access to a future evolution of states”.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-dev/attachments/20241023/739de94a/attachment-0001.htm>
More information about the amber-dev
mailing list