spec: clarify rules concerning updates during iteration
Closed this issue · 1 comments
The Go implementation dynamically rejects all attempts to update a list during iteration, except list[i] = ...
, which it considers a non-structural mutation:
$ cat ~/a.sky
def iterator1():
list = [0, 1, 2]
for x in list:
list[x] = 2 * x
return list
print(iterator1(), [0, 2, 4])
$ skylark a.sky
[0, 2, 4] [0, 2, 4]
The Java and Rust implementations reject even this.
The Go semantics came out of a discussion with the Bazel team that was never concluded. The task of this issue is to clarify the semantics for mutation during iteration. See Google Issue b/37964285 for context.
From the specification:
It is a dynamic error to mutate a sequence such as a list or a dictionary while iterating over it.
In the Go implementation:
def foo(arg):
for i in arg:
arg[0] = 5
foo([10, 11]) # allowed
foo({0: 10, 1: 11}) # error
The difference between the list and the dictionary doesn't seem consistent.
My recommendation is to follow the specification, forbid both calls (in the example above). We can easily revisit this restriction later, as this would be a backward-compatible change.