DART / CHAPTER 06
Lazy iterables and generator demand
IntermediateKnow when transformations execute and when to materialize them.
By the end of this chapter
- Trace deferred where and map operations
- Create a sync* generator
- Bound traversal before collecting results
The idea
Many Dart Iterable operations describe work that occurs only when the result is iterated. A where or map result is not necessarily a snapshot of the source. If the underlying list changes before iteration, the later traversal can observe its current contents. Call toList when the contract requires a materialized collection at that point in time.
A sync* function yields a sequence incrementally. This is useful for large or unbounded sources when a consumer needs only a prefix. Keep side effects out of reusable transformations unless their timing is intentional, because repeated iteration can repeat work. Bound an infinite sequence with take before converting it to a list, and distinguish lazy computation from a cached result.
Iterable<int> squares() sync* {
for (var n=1;;n++) { yield n*n; }
}
void main() { print(squares().take(3).join(",")); }1,4,9
The consumer requests only three values, so the generator never attempts to materialize its unbounded sequence.
Try it yourself
Generate successive batches or numeric steps lazily and collect only a requested prefix.
Use your own editor for this exercise. Runnable challenges on CodeQuest are available for JavaScript, Python, and SQL.
CHECK YOUR UNDERSTANDING