skip to content

What is the difference between yield and yieldAll inside a sequence{} block, and which overloads does yieldAll accept?

level: middleimportance: should knowfreq 45%

answer

  1. yield = 1 element; yieldAll = many
  2. yieldAll overloads: Iterable, Sequence, Iterator
  3. yieldAll stays lazy — safe on infinite sequences
  4. yieldAll(xs) == for (x in xs) yield(x)
  5. Idiomatic for recursive/flatten patterns

basics

~10 s

yield 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 s

Both 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

for a junior

Knows yield is one element and yieldAll is several.

for a middle

Lists the three overloads and the yield-loop equivalence.

for a senior

Stresses preserved laziness and uses it for recursive/flatten patterns safely.

for a principal

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

context