JDK-8300691 - final variables in for loop headers should accept updates
Brian Goetz
brian.goetz at oracle.com
Wed Oct 23 15:26:02 UTC 2024
As usual, everybody's right :)
I think Ron has captured the stewardship argument about how we would
like users to view the language: that the two sorts of loops, assuming
each are "well behaved", should be interchangeable, refactorable to each
other, etc, and that the differences in scoping should be an
"implementation detail."
And Maurizio is correct that people have formed their own mental models
about how both kinds of loops work, and for some, changing them will be
"fixing a bug", and for others, it will be taking something
straightforward (x++ in the loop header is straight mutation, nothing to
see here) and distorting it.
Given that we have the language we have, what to do here is mostly based
on a cost-benefit analysis where both the costs and benefits are
subjective. And, I think it's kind of close; I think there's a simple
thing we could do here that would be a net improvement, but we could
also justify (as we did in 8) doing nothing special here.
Honestly, I think both kinds of loops are weak; the "legacy C" loops
suffer mightily from having copied too literally (and yet poorly) from
C, with the result being that they are both too general for the average
case and too weak for the general case. The foreach loops suffers from
the (explicit) desire to capture the 90/10 point. The result being that
they both have irritating sharp edges that make you want to refactor
from one to the other, and sometimes back. Which makes gratuitous
asymmetries in how they interact with other features (scoping and
capture) even more irritating, because one forced refactoring will then
force another refactoring.
On 10/23/2024 9:52 AM, Maurizio Cimadamore wrote:
>
>
> On 23/10/2024 13:00, Ron Pressler wrote:
>> That x really means something subtly different in the foreach loop and
>> the classic loop is more of an implementation detail. I don’t know the
>> history of that choice, and it did predate lambda, but if it was made to
>> allow a final index to be captured in an index class, then
>> capturability is the motivation for that detail.
>
> I don't disagree that is a matter of perspective (I called it
> subjective). As I stated:
>
>> How you "fix" this largely depends on (a) how you find this asymmetry
>> annoying (which likely depends on exposure - and different code bases
>> might have different levels of that) and (b) how much your developer
>> intuition is trained to view the loop induction variable as a single
>> mutable *variable*, or a series of *values* where each value is
>> derived from the former in a controlled fashion. I don't have a
>> strong (enough) opinion on either :-)
>
> IMHO both (a) and (b) are subjective calls. I feel that some
> developers will stand by the asymmetry because for-each is special,
> and doesn't use mutation (no need to do `i++`) so _of course_ you get
> a "fresh" `i` on a for-each iteration (but not in an imperative for
> loop). This is further reinforced by the fact that you can add `final`
> on for-each variables, but not in the imperative loop induction variables.
>
> Other developers will find this distinction annoying, because in a
> well-behaved counted loop, the mutation of the induction variable is
> so controlled that it can largely be ignored (and be treated as an
> impl detail).
>
> I think both views have their own merits
>
> Maurizio
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-dev/attachments/20241023/2b2ea4b0/attachment.htm>
More information about the amber-dev
mailing list