Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

spec: clarify that modifying map elements in place while iterating is legal #9926

Closed
jacobsa opened this issue Feb 18, 2015 · 5 comments
Closed

Comments

@jacobsa
Copy link
Contributor

jacobsa commented Feb 18, 2015

The spec implies that adding to and removing from maps while iterating is legal by defining the semantics of doing so:

If map entries that have not yet been reached are removed during iteration, the corresponding iteration values will not be produced. If map entries are created during iteration, that entry may be produced during the iteration or may be skipped.

As far as I can tell though, it doesn't explicitly specify that existing keys may be modified but not removed. For example:

var m map[string]int

[...]

for k, v := range m {
  m[k] = v + 1
}

Is the above program guaranteed to be legal? Given the strong guarantees on adding and removing elements it seems natural to assume it would be, but explicit clarification from the spec might be good.

@minux
Copy link
Member

minux commented Feb 18, 2015 via email

@jacobsa
Copy link
Contributor Author

jacobsa commented Feb 19, 2015

I'm not sure that "adding and removing are safe" strictly implies "modifying in place is safe", but okay. Like I said, it seems natural to assume.

But more importantly, the spec doesn't actually say that removing the current entry is legal. It says only "entries that have not yet been reached". So my reading is that even this code, which only removes, is not guaranteed to be legal:

var m map[string]int

[...]

for k, _ := range m {
  delete(m, k)
}

Again this may be because the intent is only to specify what would happen in a situation where it's not clear whether the values would be produced or not. But that still leaves open the question of whether it is safe to remove/modify the current entry. You could for example imagine a map implementation that involves a linked list, where the unlink operation sets the next pointer of the node you're currently looking at to nil.

@minux
Copy link
Member

minux commented Feb 19, 2015 via email

@ianlancetaylor
Copy link
Contributor

I think the key to understanding this is to realize that while executing the body of a for/range statement, there is no current iteration. There is a set of values that have been seen, and a set of values that have not been seen. While executing the body, one of the key/value pairs that has been seen--the most recent pair--was assigned to the variable(s) of the range statement. There is nothing special about that key/value pair, it's just one of the ones that has already been seen during the iteration.

I think that once you understand that the meaning of any operation involving the "current" entry is clear.

@jacobsa
Copy link
Contributor Author

jacobsa commented Feb 19, 2015

@ianlancetaylor: I see, thank you for explaining.

@golang golang locked and limited conversation to collaborators Jun 25, 2016
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants