4 ms·
It is crazy that such behaviour even gets deployed It is so unintuitive...
by tester756 3y ago
It is crazy that such behaviour even gets deployed
It is so unintuitive...
- wahern 3y agoIt's unintuitive to users of the language, but it's very intuitive from the perspective of those implementing the language. Everybody seems to make this mistake. Lua 5.0 (2003) made this mistake, but they fixed it in Lua 5.1 (2006). (Lua 5.0 was the first version with full lexical scoping.)
- tester756 3y ago>It's unintuitive to users of the language, but it's very intuitive from the perspective of those implementing the language. It sounds like a lack of dogfooding, lack of review?
- catach 3y agoTo the degree the the implementers are also users they carry their implementer understanding into their use. Dogfooding doesn't help when your understanding doesn't match that of your users.
- skywhopper 3y agoThe problem is that the error conditions are relatively rare. Most of the time it doesn’t break anything. So even with dogfooding you can miss it or not see it as a problem early on. But after 10 years of evidence that it was a mistake, that it’s almost never intended, and the fix won’t break much if anything, it’s time to fix it.
- masklinn 3y agoNo, it’s just an obvious behaviour when you understand how the language works.
- tester756 3y ago"if you learned how this work, then you understand this behaviour" I disagree with this approach, despite the fact that you can logically explain this, then it still is terrible design and as you see golang (and c# and other langs) designers realized it too and changed it So, how can you even try to defend this design when even the designers decided to change it (despite the fact that changing lang is really hard)?
- masklinn 3y ago> I disagree with this approach That is not actually relevant to the point. > So, how can you even try to defend this design I'm doing no such thing, I'm pointing out that your reasoning is faulty: dogfooding does not help when the behaviour is logical and obvious to the designer-cum-user, and same with reviewing.
- tester756 3y ago>dogfooding does not help when the behaviour is logical and obvious to the designer-cum-user, and same with reviewing. While I can agree with dogfodding, then review doesn't have to be done just by the people that are responsible for the design/impl. You can have external reviewers for (let's call it) sanity check
- gtowey 3y agoIt's not crazy. It's just the difference between a pointer and a value, which is like comp sci 101. I think the main things that make it such a trap is that the variable type definition is implicit so the fact that it's a pointer becomes a bit hidden, and that easy concurrency means the value is evaluated outside of the loop execution more often.
- tester756 3y ago>It's not crazy. No. Full disagree. Array represents a concept of holding multiple values (let's simplify) of the same type. Loop (not index based) over array represents concept of going *over* array's elements and executing some code body for each of it. Now, if the behaviour isn't that loop's body is executed for each array element (let's forget about returns, breaks, etc) then the design is terrible (or implementation, but that'd mean that it was a bug) I have totally no idea how can you design this thing in such a unintuitive way unless by mistake/accidentally.
- jrockway 3y agoThe loop semantics do not have anything to do with arrays. The point of confusion is whether a new slot for data is being created before each iteration, or whether the same slot is being used for each iteration. It turns out that the same slot is being used. The Go code itself is clear `for i := 0; i < 10; i++`. `i := 0` is where you declare i. Nothing else would imply that space is being allocated for each iteration; the first clause of the (;;) statement is only run before the loop. So you're using the same i for every iteration. This is surprising despite how explicit it is; programmers expect that a new slot is being allocated to store each value of i, so they take the address to it, and are surprised when it's at the same address every iteration. (Sugar like `for i, x := range xs` is even more confusing. The := strongly implies creating a new i and x, but it's not doing that!) Basically, here are two pseudocode implementations. This is what currently happens: i = malloc(sizeof(int)) *i = 0 loop: <code> *i = *i + 1 goto loop if *i < 10 This is what people expect: secret = malloc(sizeof(int)) *secret = 0 loop: i = malloc(sizeof(int)) *i = *secret <code> *secret = *secret + 1 goto loop if *secret < 10 You can see that they are not crazy for picking the first implementation; it's less instructions and less code, AND the for loop is pretty much exactly implementing what you're typing in. It's just so easy to forget what you're actually saying that most languages are choosing to do something like the second example (though no doubt, not allocating 8 bytes of memory for each iteration). Remember, simple cases work: for i := 0; i < 10; i++ { fmt.Println(i) // 0 1 2 3 4 ... } It's the tricky cases that are tricky: var is []*int for i := 0; i < 10; i++ { is = append(is, &i) } for _, i := range is { fmt.Println(*i) // 9 9 9 9 9 ... } If you really think about it, the second example is exactly what you're asking for. You declared i into existence once. Of course its address isn't going to change every iteration.
- baq 3y agoThe problem is when it doesn't matter at first and then your language and its use evolves.