Why number of iteration of this loop is not fixed

why number of iteration of this loop is not fixed? each time I execute this code, I observe different number of iterations.

package main

import "fmt"

func main() {

	m := make(map[string]string)
	m["A"] = "Apple"
	for key, val := range m {
		fmt.Printf("key=%v, val=%v\n", key, val)
		m[key+"a"] = val
	}
}

From the language specification about iterating using range:

The iteration order over maps is not specified and is not guaranteed to be the same from one iteration to the next. If a map entry that has not yet been reached is removed during iteration, the corresponding iteration value will not be produced. If a map entry is created during iteration, that entry may be produced during the iteration or may be skipped. The choice may vary for each entry created and from one iteration to the next. If the map is nil, the number of iterations is 0.

The number of iterations is fixed, the order isn’t.

[LE] This strange effect happened to you because of this instruction:

m[key+"a"] = val

Thank you for the language specification reference.

So it means if we put a new entry during map iteration, it is not guaranteed that a new entry will be created in map. Is my understanding correct??

Also, I want to understand why this king implementation in Golang?

We get ConcurrentModififcationException in Java if we try to put in map during map iteration. My understanding was: as Golang does not panic for this scenario then it should be an infinite loop.

Could you please explain to me in more detail so it will help me to understand this concept?

Thank you.

Yes, I understand it. But I want to understand why the un-predictable number of iteration here. As per my understanding, it should be an infinite loop because in each iteration I am adding a new entry to map so after each iteration we will have a new entry in the map to iterate.

No, this is not correct.

If you put a new entry in the map during iterating the same map, it will be added, though it is not guaranteed that the new element will be iterated over.

You can inspect your map after the loop, all your elements, even the non-iterated will be there.

You can assume that go does roughly the following when iterating over a map, at least semantically:

  1. Get a list of keys
  2. Randomize its order
  3. While iterating keep an index at where in this list we are now

When you then add an entry to the map, it will also create a corresponding entry in the list of keys, but it will put that at a random position in the list and bump the current position if the entry was added to the left (to avoid double iteration of a key) or leave the index as is when inserted at a higher position.

If the new key was inserted at a higher position, we will encounter it during iteration, if it was added at a lower position, we will not see it.

3 Likes

Thank you very much for explaining in detail.