The surprise factor is only for the current generation of people who are used to it
and who are used to other languages that the same kind of for loop and closures that can escape (basically only JS?)
But the internal consistency between the for;; and for range allows you never doubt about the rule again once you first learned it. Yes, there is the risk that you'll get it wrong once (if you first learn the language or if you are used to the old rules) but if the language authors had only fixed for range, then a lot more people would get for;; wrong just because they would be never sure which way it would be.
So the only "solution" would be to never fix "for range" or disallow for :=;; ?
In any case I think that if you really care about the old semantics, it's not a bad idea to making it obvious to the reader that you intend to directly or indirectly take a reference to the iteration variable and that it effectively survives the loop body with:
The core problem here is that "Go promotes explicitness" ended at Go 1.21. Since Go 1.22, it is no longer valid.
The change of "for-range" loops is good is because no implicit code is introduced.
And the change of "for;;" loops is bad is because implicit code is introduced. Implicitness often causes surprises. The implicit line
pa_last, pb_last, pc_last = &a, &b, &c
in the new semantics is absolutely an evil.
And the seriousness of this problem is that, if you upgrade your go version in go.mod files, the behavior of the your old code might change. And the change might be not always easily found in time.
> but if the language authors had only fixed for range, then a lot more people would get for;; wrong just because they would be never sure which way it would be.
This is just a problem in theory, it is never proven (and now no chance to prove it).
> So the only "solution" would be to never fix "for range" or disallow for :=;; ?
I think it is just fine to only make changes on "for-range" loops, just as C# have done. The assumed problem of "for;;" loops is never proven, or just proven to be tiny.
IMHO, it is just rsc's personal willing to make the change. This might be the worst decision made in Go history.
But the internal consistency between the for;; and for range allows you never doubt about the rule again once you first learned it. Yes, there is the risk that you'll get it wrong once (if you first learn the language or if you are used to the old rules) but if the language authors had only fixed for range, then a lot more people would get for;; wrong just because they would be never sure which way it would be.
So the only "solution" would be to never fix "for range" or disallow for :=;; ?
In any case I think that if you really care about the old semantics, it's not a bad idea to making it obvious to the reader that you intend to directly or indirectly take a reference to the iteration variable and that it effectively survives the loop body with: