Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

The 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.


>The loop semantics do not have anything to do with arrays.

Loop in general or "for each" style loop, that's huge difference.

The 2nd one has a lot to do with collections.

>You can see that they are not crazy for picking the first implementation; it's less instructions and less code

Yes, it is not crazy when you're looking at it from the reverse engineering / implementation side

but if you start thinking about it from user's perspective then it is very bad behaviour

because they used "foreach" like loop which is a concept of walking thru every element of collection.


I still don't see how looping over a collection is different from looping over a sequence of numbers from 1 to n.


Depends what do you actually mean by sequence, but mostly purpose.

Normal "for" is like: repeat this code body as long as condition is satisfied

Foreach is more like: walk thru this collection

Look (c#):

foreach (var item in items) ...

for (int i=0; i<10; i++) { }

In the 2nd version it is possible to jumps ahead, back, do not move, etc. Generally play around "i's" values

Meanwhile I haven't seen yet any1 trying to do anything like this in foreach, because it is meant for just walking thru collection


I'm getting 10s for your last code example (not 9s)


Ah yup. I didn't test it and you normally never see i after that last increment!




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: