google/skylark

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.

@laurentlb

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.