Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Pass a lazy expression to a consumer

A generator expression evaluates one element at a time, when its consumer asks for the next one:

def square(n: i64) -> Result[i64, OverflowError[i64]]:
    Ok(n * n)

def main() -> Result[(), AllocError | IoError | OverflowError[i64]]:
    squares = (square(n) for n in range(4) if n != 2)
    mut values: list[i64] = []?
    for outcome in squares:
        values.append(outcome?)?
    print(values)?
    words = ["tea", "", "café"]?
    print(", ".join(w for w in words if w != "")?)?
    Ok(())
[0, 1, 9]
tea, café

The square helper returns a Result because arbitrary i64 squares can overflow. The generator yields those results without unwrapping them; the loop uses ? in main before appending each value. A caller’s arithmetic mode never changes a producer’s declared contract.

separator.join accepts any iterable of str, so the selected words are joined without first collecting them into a list. A generator cannot be measured in advance, so join grows a scratch buffer as pieces arrive; a list, set, or dictionary is measured first and needs only the result’s allocation. A consumer that stops early, such as the pipeline method any, leaves the remaining elements unevaluated.

The outer source evaluates when the generator is created. Filters, elements, and inner for sources evaluate on demand. The generator owns its sources and copies or moves any enclosing local values it uses; copied captures are snapshots. Borrowed inputs are unsupported because a suspended frame cannot retain a reference into its caller. Use copy(values)? to preserve an owned list, or consume a borrowing pipeline locally instead.

Parentheses can be omitted for a sole argument. With additional arguments, write consume((n for n in source), other). Generator expressions follow the same ownership, cleanup, and yield restrictions as generator functions; they require no intermediate list or heap-allocated frame. A fallible operation in their body must be handled explicitly, since ? cannot propagate out of a suspended generator.