What is the difference between yield and yieldAll inside a sequence{} block, and which overloads does yieldAll accept?
answer
- yield = 1 element; yieldAll = many
- yieldAll overloads: Iterable, Sequence, Iterator
- yieldAll stays lazy — safe on infinite sequences
- yieldAll(xs) == for (x in xs) yield(x)
- Idiomatic for recursive/flatten patterns
basics
~10 syield emits one element. yieldAll emits a whole group at once. yieldAll works with a list/iterable, another sequence, or an iterator — and it stays lazy.
solid answer
~40 sBoth are suspending members of SequenceScope. `yield(value: T)` emits a single element then suspends until the next pull. `yieldAll` is a convenience for emitting many elements without a manual loop; it has three overloads: `yieldAll(elements: Iterable<T>)`, `yieldAll(sequence: Sequence<T>)`, and `yieldAll(iterator: Iterator<T>)`. Crucially, the `Sequence` and `Iterator` overloads preserve laziness: passing an infinite sequence to yieldAll does not force it — elements are still pulled one at a time as the consumer requests them. The `Iterable` overload also iterates lazily over the source. yieldAll is just sugar; `yieldAll(xs)` is equivalent to `for (x in xs) yield(x)` but reads cleaner and is the idiomatic way to splice one sequence into another.
go deeper
Knows yield is one element and yieldAll is several.
Lists the three overloads and the yield-loop equivalence.
Stresses preserved laziness and uses it for recursive/flatten patterns safely.
Reasons about composition cost and when manual yield vs yieldAll affects readability and allocation in hot code.
## yield: one element `yield(value: T)` is a suspending function on `SequenceScope<T>` that hands a **single** element to the consumer and then suspends the producer until the next element is requested. ## yieldAll: many elements `yieldAll` emits **multiple** elements in one call. It has three overloads: - `yieldAll(elements: Iterable<T>)` — splice in any collection/iterable. - `yieldAll(sequence: Sequence<T>)` — splice in another (possibly lazy/infinite) sequence. - `yieldAll(iterator: Iterator<T>)` — splice in a raw iterator. It is semantically equivalent to looping with `yield`: ```kotlin // these two produce the same sequence sequence { yieldAll(listOf(1, 2, 3)) } sequence { for (x in listOf(1, 2, 3)) yield(x) } ``` ## Laziness is preserved The key subtlety: `yieldAll` does **not** eagerly materialize its argument. Splicing an infinite sequence is safe — each element is still produced on demand: ```kotlin val naturals = generateSequence(1) { it + 1 } // infinite val combined = sequence { yield(0) yieldAll(naturals) // does NOT hang; pulled lazily } println(combined.take(4).toList()) // [0, 1, 2, 3] ``` This makes `yieldAll` the idiomatic tool for composing/flattening sequences inside a builder — e.g. recursive tree traversal where each node yields itself then `yieldAll`s its children's sequence. ## Common use: flatten/recurse ```kotlin fun <T> Tree<T>.preorder(): Sequence<T> = sequence { yield(value) for (child in children) yieldAll(child.preorder()) } ``` Here `yieldAll` recursively splices each child's lazy sequence into the parent's, and the whole traversal stays lazy. ## Gotcha Don't confuse `yieldAll(seq)` with calling `seq.toList()` first — the latter forces eager evaluation and would hang on an infinite source.
- Is yieldAll(infiniteSequence) safe?Yes. yieldAll pulls lazily, so as long as the consumer takes a finite prefix it only produces the requested elements and never hangs.
- How would you rewrite yieldAll(list) using only yield?for (x in list) yield(x) — yieldAll is just sugar for that loop.
saying these in an interview costs you the question
- Claiming yieldAll materializes its argument into a list first
- Saying yieldAll only accepts a List
- Thinking yieldAll on an infinite sequence will hang
- Not knowing yieldAll has Iterator/Sequence overloads