5.1.15. Iterators and Generators
This tutorial covers built-in iterators (range, each, keys,
values), creating generators with yield, and making custom types
iterable.
5.1.15.1. Built-in iterators
Arrays, ranges, tables, and strings are all iterable:
for (i in range(5)) { ... }
for (v in my_array) { ... }
for (k, v in keys(table), values(table)) { ... }
5.1.15.2. Generators
A generator lazily produces values one at a time using yield.
Generators use $ (either $ { } or $() { }):
var counter <- generator<int>() <| $ {
for (i in range(5)) {
yield i
}
return false
}
for (v in counter) {
print("{v} ") // 0 1 2 3 4
}
Generators maintain state between yields — local variables keep their values across calls.
5.1.15.3. Generator patterns
Filtering — yield only matching values:
var evens <- generator<int>() <| $ {
for (i in range(10)) {
if (i % 2 == 0) { yield i }
}
return false
}
Stateful — maintain running computations:
var fibs <- generator<int>() <| $ {
var a = 0
var b = 1
while (a < 100) {
yield a
let next = a + b
a = b
b = next
}
return false
}
5.1.15.4. Custom iterable types
Define an each() function to make any struct iterable:
struct NumberRange {
low : int
high : int
}
def each(r : NumberRange) : iterator<int> {
return <- generator<int>() <| $ {
for (i in r.low .. r.high) {
yield i
}
return false
}
}
var r = NumberRange(low=3, high=8)
for (i in r) {
print("{i} ") // 3 4 5 6 7
}
Note
Generators are one-shot — once exhausted they produce no more values. Create a new generator to iterate again.
See also
Iterators, Generators in the language reference.
Full source: tutorials/language/15_iterators_and_generators.das
Next tutorial: Modules and Program Structure