Pure vs. Impure Iterators in Go
15 comments
·May 29, 2025pansa2
masklinn
It's more between repeatable iterables and one-shot iterables (of which iterators are a subset, as iterators are iterable). For instance a file is an iterable, but (unless it's seekable and you rewind it) it'll only let you iterate once.
Basically what Go calls an iterator most other language call an iterable. Because it uses internal iteration, Go doesn't hand out iterators (save through iter.Pull).
catlifeonmars
This is the same in JavaScript. There is “pure” Iterable protocol which produces an “impure” Iterator. Interestingly , for loops in JavaScript do not work directly with Iterators; to use in a for loop you must wrap an Iterator in an Iterable
codr7
Java is the same if I remember correctly, always felt like a design failure to me.
masklinn
It's especially dumb for Java, because Iterator could just have been a subtype of Iterable. That's basically what Python does, the iterator protocol requires also being an iterable[0]. And Rust just blanket implements IntoIterator for every Iterator without asking.
At least it's pretty easy to wrap an iterator in JS:
{[Symbol.iterator]: () => it}
[0] which in the rare case you implement an iterator entirely by hand will be a trivial `return self`, so much so that `collection.abc.Iterator` just provides that)tapirl
Be careful there are bugs and design flaws in Go iterators: https://go101.org/blog/2025-03-15-some-facts-about-iterators...
jub0bs
Your post does show that iterators are somewhat of a leaky abstraction, but I'm not sure I would go as far as calling some of their infelicities "bugs". Whether those infelicities matter in practice is a moot point.
tapirl
The bug is confirmed: https://github.com/golang/go/issues/71685
jub0bs
Ok, that is annoying. I hope it gets fixed soon.
catlifeonmars
- My initial thought is that the performance implication (e.g. escaping to the heap) of impure iterators is an implementation detail and seems like a good candidate for a future compiler optimization.
- impure iterators are strictly more powerful than pure iterators in that they can be resumed but do not have to be. If I wanted to pick one pattern for consistent behavior across all iterators it would be this one.
gregwebs
Not all impure iterators can be resumed. But any pure iterator can be converted to a resumable iterator with a generic conversion function.
catlifeonmars
> any pure iterator can be converted to a resumable iterator with a generic conversion function.
Makes sense
> Not all impure iterators can be resumed
How do you mean? In my head resuming an iterator is just partially unrolling a loop.
nine_k
An impure iterator can panic, so you can't resume?
shubhjain
Are the wordings "pure" vs "impure" suitable here, or should it have been "stateless" vs "stateful"?
euroderf
Great! How about iterators on trees ? Multiple options to provide.
> Most iterators provide the ability to walk an entire sequence [...] Calling the iterator again walks the sequence again.
> "Single-use iterators" break that convention, providing the ability to walk a sequence only once.
This seems similar to the difference between an "iterable" and an "iterator" in Python (and between `IEnumerable` and `IEnumerator` in C#).
A Python list `l = [1, 2, 3]` is an iterable, and you can do `for v in l: print(v)` multiple times. But `iter(l)` is an iterator and `for v in i: print(v)` will only work once.