Skip to content(if available)orjump to list(if available)

Pure vs. Impure Iterators in Go

Pure vs. Impure Iterators in Go

15 comments

·May 29, 2025

pansa2

> 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.

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

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.