Yield and lazy sequences¶
Use yield value; to produce one element and pause a function. The next request resumes
immediately after that statement. yield break; ends the sequence; reaching the end does too.
At a glance
fun positives(values: int[]): Iterable<int> {
for (let value in values) {
if value > 0 {
yield value;
}
}
}
yield value;produces one element and pauses the function until the next one is requested.yield break;ends the sequence early.
import system;
fun numbers(count: int): Iterable<int> {
for (let i = 0; i < count; i++) {
yield i;
}
}
fun main(): void {
let values = numbers(3);
for (let value in values) {
System.println(value);
} // 0, 1, 2
for (let value in values) {
System.println(value);
} // 0, 1, 2 again
}
Calling numbers captures its arguments without running its body. Each loop creates a fresh
cursor, so the sequence can be enumerated repeatedly or by independent consumers. Reference
arguments keep their usual shared identity; enumeration does not snapshot their contents.
Value struct receivers get an independent copy for each cursor.
continue; skips a loop iteration. It does not produce a value. There is no yield continue
or yield return spelling.
fun positives(values: int[]): Iterable<int> {
for (let value in values) {
if value == 0 {
yield break;
}
if value < 0 {
continue;
}
yield value;
}
}
Asynchronous sequences¶
An async iterator declares AsyncIterable<T> and may await between elements. Calling it returns
the sequence directly. Use await for inside an async function to consume it:
import system;
async fun delayed_numbers(count: int): AsyncIterable<int> {
for (let i = 0; i < count; i++) {
Time.sleep(100).await;
yield i;
}
}
async fun main(): void {
await for (let value in delayed_numbers(3)) {
System.println(value);
}
}
Only requested elements are produced. Ordinary async functions still return Future<T>.
Cursor access and cleanup¶
Iterable<T>.iterator() returns an Iterator<T>; its next() returns Option<T>.
AsyncIterable<T>.iterator() returns an AsyncIterator<T> whose next() returns
Future<Option<T>>. Both cursors have close(): void, which ends iteration and releases suspended
producer state. Repeated close is harmless; advancing a closed cursor returns None.
| Type | Member | Returns |
|---|---|---|
Iterable<T> |
iterator() |
A fresh Iterator<T> |
Iterator<T> |
next() |
Option<T>; None when the sequence has ended |
Iterator<T> |
close() |
— |
AsyncIterable<T> |
iterator() |
A fresh AsyncIterator<T> |
AsyncIterator<T> |
next() |
Future<Option<T>>; None when the sequence has ended |
AsyncIterator<T> |
close() |
— |
All four types are available without an import.
Loops close their cursors when exhausted or exited early, including return. Manual cursor
consumers should close cursors when finished. Cancelled consumers close their active cursor when
the Future frame is released. An async cursor permits one pending advancement
at a time. Closing it cancels its producer and wakes pending advancement with None.
Statements at a glance¶
| Statement | Where | Effect |
|---|---|---|
yield value; |
Yield function | Produces one element and pauses until the next is requested |
yield break; |
Yield function | Ends the sequence |
continue; |
Loop in a yield function | Skips to the next loop iteration without producing a value |
for (let x in seq) { … } |
Anywhere | Consumes an Iterable<T> and closes its cursor when the loop exits |
await for (let x in seq) { … } |
async function |
Consumes an AsyncIterable<T> and closes its cursor when the loop exits |
Rules¶
- Named functions and methods, including generic methods, support yield.
- Synchronous yield functions declare
Iterable<T>; async yield functions declareAsyncIterable<T>. - Yielded values must be assignable to
T. - Use
yield breakinstead of an ordinaryreturninside a yield function. - Yield is not supported in lambdas or property accessors.
- Iterator parameters cannot be
reforborrow; stack-only values cannot escape into suspended state. - Suspension inside
lockordeferis rejected.
Run the complete example with dream run sample/iterators/yield.dream.