~/Go Iterators Are Concerning

Oct 22, 2024


Consider Python generators.

1
2
def simple_generator():
    yield 1

A simple function generator which clearly expresses the idea of yielding some value.

Go has decided to use a much less readable syntax, though I’d have to grant that Go is strongly typed and thus requires more literal typing to express what a function may or may not take or return. That being said, Iterators in Go are more verbose and seem to have arbitrary limitations on their use in regular code.

The return type of an Iterator is not concise and so two new types were added to the library, Seq and Seq2 the first for iterators that yield a single value and the second for iterators which yield two values.

1
2
type Seq[V any] func(yield func(V) bool)
type Seq2[K, V any] func(yield func(K, V) bool)

Consider the following snippet taken from go.dev and contrast it with Python generators

1
2
3
4
5
6
7
8
9
func (s *Set[E]) All() iter.Seq[E] {
    return func(yield func(E) bool) {
        for v := range s.m {
            if !yield(v) {
                return
            }
        }
    }
}

The main problem is the amount of line noise.

To take a step back and read this out loud. We’re defining a function which returns a function which takes a function, which takes an argument of type E and returns a bool. When we expand this all out we get this

1
 func (s *Set[E]) All() func(yield func(E) bool)

Looking past the definition, I was surprised to realize that yield is not a keyword in itself, similar to how argv and argc are just variable names enforced only by convention.

References

Tags: [Go]