6 ms·
Since Go 1.22, loop {for I, p:= 0, new(int); p = &I; {p = &I}} might never exit
- Someone 3y agoC# made that change in C# 5 (2012) (https://ericlippert.com/2009/11/12/closing-over-the-loop-variable-considered-harmful-part-one/ https://ericlippert.com/2009/11/12/closing-over-the-loop-var...) Swift 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-go-vs-swift/ 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/0007-remove-c-style-for-loops.md https://github.com/apple/swift-evolution/blob/main/proposals...)
- saurik 3y agoI 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.
- electroly 3y agoOP misunderstood but you have it right. C# did not change the behavior of "for" loops; they only changed "foreach" loops. As an example: List<Action> list = new(); for (var i = 0; i < 10; i++) list.Add(() => Console.WriteLine(i)); foreach (var action in list) action(); This (still) prints all 10s. All of the closures are referencing the same "i".
- tapirl 3y agoI 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.
- electroly 3y agoI 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.
- tapirl 3y agoPlease note that, the Go proposal is for both "for-range" loops and traditional "for;;" c-like loops. I think it is okay to make the change for "for-range" loops, but not okay for traditional "for;;" c-like loops.
- parasense 3y agoI'm not persuaded the issue as given by the Reddit OP is worth the lack of progress.
- Sohcahtoa82 3y agoCan someone ELI12 what's happening here? I haven't had the pleasure of learning Go yet.
- room271 3y agoGo 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.
- tapirl 3y agoNot exactly. I'm fan of the change for "for-range" loops, but not a fan for the change for "for;;" loops.
- HillRat 3y agoGo 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.
- tapirl 3y agoIn 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".
- arp242 3y agoAll 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.
- tapirl 3y agoThe change for "for-range" loops generally has positive effects (except that it will hurt performance sometimes). But the change for "for;;" loops has many bad effects.
- Pinus 3y agoIs the code, as shown in the HN headline, correct? An exclamation mark seems to have gone missing, compared to the Reddit version.