I was shocked that C# would make this change--which is specifically to modify the scoping semantics of a C-style for loop to match those of a for-in loop, not to merely change the semantic of for-in loops; the latter seems entirely reasonable... while the former is just ridiculous to me (and OMG I am so glad I don't code in Go ;P)--but, the reference you cited for that in fact states the exact opposite: that they would never do such a strange thing (and, thereby, agrees with the person on reddit who made this post and who is adamantly against this change).
> We have this same problem in for blocks, but for blocks are much looser about what “the loop variable” is; there can be more than one[1. or none at all.] variable declared in the for loop header, it can be incremented in odd ways, and it seems implausible that people would consider each iteration of the for loop to contain a fresh crop of variables. When you say for(int i; i < 10; i += 1) { ... } it seems dead obvious that the i += 1 means “increment the loop variable” and that there is one loop variable for the whole loop, not a new fresh variable i every time through!
> We certainly would not make this proposed change apply to for loops.
I don't misunderstand it. I know the facts in C#. But the Go proposal is different. The proposed change is for both "for;;" loops and "for-range" loops.
I was referring to the HN poster "Someone" at the beginning of this subthread, my apologies for the confusion--I didn't want to name them explicitly in my post since that feels a little aggressive. They said C# 5 made this change, which is wrong; that's why I explained with a C# snippet. This subthread isn't referring to your post at all.
Go is changing the semantics of its for loops and the user is not a fan of this - at least in the subtleties. Most people, from what I can tell, are very much for this change. And note, Go is introducing quite sophisticated backwards compatibility features to avoid changing semantics for programs that are need the old behaviour.
Go loops define pointers for scope-defined variables at the loop, rather than iteration, level, so there's a common "gotcha" where you intern a pointer to access it outside of the loop (such as pushing it onto an array), and then discover that its value is clobbered by subsequent runs of the loop. There is a proposal to change this, since it's a source of confusion and bugs, particularly when `range`ing over pointers.
What the code snippet demonstrates is that, for a contrived scenario, the proposal in question also creates an unexpected result when you expect pointers to remain stable between loop iterations. To be honest, I can't think of any time where this would be an issue for me (as opposed to writing `foo := foo`); Go has quite a bit of cognitive friction in its loop semantics, so anything to reduce unexpected behavior is welcome to my mind.
In short, the new proposed Go semantics automatically declared an inside variable which has the same name as the iteration variable "I". So the inside "I" is not the iteration variable "I".
All loops run the risk of never exiting; it's basically how loops work.
This construct seems highly artificial. Perhaps it's an issue in some other less artificial cases, but the change does solve a high number of common errors, so overall it seems like a net win. I don't really see the problem here.
Sorry, it looks the HN backend edited the title automatically. The condition should be "p != &I". (BTW, the HN backend also auto changed all "i" to "I").
17 comments
[ 2.2 ms ] story [ 48.5 ms ] threadSwift had the problem in C-style for loops but not in “for…in” loops (https://www.timekl.com/blog/2015/11/26/variable-capture-in-g...), but got rid of it when it removed C-style for loops altogether in Swift 3 (September 2016) (https://github.com/apple/swift-evolution/blob/main/proposals...)
> We have this same problem in for blocks, but for blocks are much looser about what “the loop variable” is; there can be more than one[1. or none at all.] variable declared in the for loop header, it can be incremented in odd ways, and it seems implausible that people would consider each iteration of the for loop to contain a fresh crop of variables. When you say for(int i; i < 10; i += 1) { ... } it seems dead obvious that the i += 1 means “increment the loop variable” and that there is one loop variable for the whole loop, not a new fresh variable i every time through!
> We certainly would not make this proposed change apply to for loops.
I think it is okay to make the change for "for-range" loops, but not okay for traditional "for;;" c-like loops.
What the code snippet demonstrates is that, for a contrived scenario, the proposal in question also creates an unexpected result when you expect pointers to remain stable between loop iterations. To be honest, I can't think of any time where this would be an issue for me (as opposed to writing `foo := foo`); Go has quite a bit of cognitive friction in its loop semantics, so anything to reduce unexpected behavior is welcome to my mind.
This construct seems highly artificial. Perhaps it's an issue in some other less artificial cases, but the change does solve a high number of common errors, so overall it seems like a net win. I don't really see the problem here.
But the change for "for;;" loops has many bad effects.