Skip to Content

Iterator

for-in is built on the Iterator<T> protocol: any type implementing it can be iterated. Lists, sets, maps, arrays, ranges, and strings all plug into this one protocol.

Protocol shape

Iterator<T> is declared in std::Collections:

protocol Iterator<T> { func MoveNext() -> bool; func Current() -> T; func GetIterator() -> Iterator<T>; func Contains(item: T) -> bool; }

The machinery of for-in: each round calls MoveNext() first; if it returns true, Current() fetches the value and the loop body runs; if it returns false, the loop ends. GetIterator() is called on each iteration to obtain a cursor. Contains rides on the protocol so that in membership tests and iteration share one contract.

In a type annotation position, the protocol name needs import Collections.*; to activate the bare name, or use Collections.Iterator<T> directly.

Custom iteration

Implement the four members and your own type plugs into for-in:

import Collections.*; class Countdown impl Iterator<int> { var n: int = 0; init(from: int) { n = from; } public func MoveNext() -> bool { n -= 1; return n >= 0; } public func Current() -> int => n; public func GetIterator() -> Iterator<int> => self; public func Contains(item: int) -> bool => item >= 0 && item <= n; } val c = new Countdown(3); print(c.Contains(2)); for x in c { print("tick", x); }
True tick 2 tick 1 tick 0

MoveNext advances first and reports after, so the first value produced is 2. This example’s GetIterator returns self, meaning the cursor is the object itself.

Independent cursors

Nest two levels of for-in over the same list and the two levels stay out of each other’s way:

val xs = new list<int>(); xs.Add(1); xs.Add(2); for x in xs { for y in xs { print(x, y); } }
1 1 1 2 2 1 2 2

Every iteration over a standard container gets its own cursor object; the inner loop finishing does not disturb the outer loop’s progress. Do the same when implementing your own container: have GetIterator() return a fresh cursor object rather than self — unless your type is a one-shot iterator by design.

Notes

  • The iteration-variable position of for-in is a pattern position; a list of tuples can be destructured directly (for (n, s) in xs; same for list.Zip and map.Entries()).
  • Iterating a map yields values, an array yields elements, and a string yields characters by grapheme cluster — see Unicode and grapheme clusters.
  • x in coll membership tests go through the protocol’s Contains member: lists and arrays do an O(n) linear scan, sets use hash equality — pick your data structure with hot paths in mind.
Last updated on October 11, 2026