What does merge do with multiple Flows, and how does it differ from zip and combine?
answer
- merge = concurrent fan-in, no transform
- Items pass through unchanged, interleaved by arrival
- All sources must share the element type
- Completes only when every source completes
- flattenMerge for a Flow<Flow<T>> with concurrency limit
basics
~10 smerge runs several flows at once and forwards each item as it arrives into one flow. It does not pair or transform values — it just interleaves them in arrival order.
solid answer
~40 smerge takes multiple Flows of the same type and collects them concurrently, re-emitting every element from every source into a single flow as soon as it appears. Unlike zip and combine, merge does not join values together: there is no transform lambda and no pairing — each upstream item passes through unchanged. The output order is the interleaving of arrival times across sources, so it is non-deterministic when sources race. The merged flow completes only after all sources complete; if any source throws, the exception propagates and the others are cancelled. It is exposed as a top-level function merge(vararg flows) and as Iterable<Flow<T>>.merge() / Flow<Flow<T>>.flattenMerge(). Use merge to fan in homogeneous event streams (e.g. several sensors) into one pipeline.
code
kotlin · 9 linesimport kotlinx.coroutines.flow.*
val a = flowOf(1, 2)
val b = flowOf(10, 20)
// No lambda: values are forwarded untouched, interleaved by arrival
merge(a, b).collect(::println) // e.g. 1, 10, 2, 20
// Collection form
listOf(a, b).merge().collect(::println)go deeper
Knows merge interleaves items from several flows into one without transforming them.
Explains concurrent collection, same-type requirement, arrival-order interleaving, and completion-after-all semantics.
Contrasts merge with zip/combine on the value-correlation axis and reaches for flattenMerge with a concurrency limit when flattening a flow-of-flows.
Reasons about structured-concurrency error propagation, non-determinism implications for testing, and bounding fan-in concurrency under load.
## What `merge` is `merge` is the **fan-in** combiner. Given several `Flow<T>` of the **same element type**, it returns a single `Flow<T>` that collects all of them **concurrently** and forwards each emitted item the instant it arrives. There is **no transform lambda** and **no pairing**: values are passed through untouched and simply **interleaved**. ```kotlin import kotlinx.coroutines.flow.merge import kotlinx.coroutines.flow.flowOf val clicks = flowOf("click") val keys = flowOf("key-A", "key-B") merge(clicks, keys).collect(::println) // prints click, key-A, key-B in arrival order (timing-dependent) ``` ## Forms of the API - `merge(vararg flows: Flow<T>): Flow<T>` — top-level. - `Iterable<Flow<T>>.merge(): Flow<T>` — extension on a collection of flows. - `Flow<Flow<T>>.flattenMerge(concurrency = N)` — flattens a flow-of-flows, with a configurable concurrency limit (`merge` is essentially `flattenMerge` with default concurrency). ## Semantics that matter - **Concurrency:** all sources are collected at the same time, each in its own child coroutine of the collecting scope. - **Ordering:** output reflects **arrival order**; with racing sources it is **non-deterministic**. - **Completion:** the merged flow completes only after **every** source completes. - **Errors / cancellation:** an exception in any source propagates to the collector and **cancels the siblings** (structured concurrency). ## How it differs from `zip` / `combine` | Operator | Joins values? | Output type | Triggered by | |---|---|---|---| | `zip` | yes (lockstep pairs) | transformed `R` | both sides ready for index *n* | | `combine` | yes (latest-of-each) | transformed `R` | any source, after all seeded | | `merge` | **no** | same `T`, untouched | any source, immediately | So `zip`/`combine` **correlate** values into a new shape, while `merge` simply **flattens** independent streams of one type into one. ## When to use Fan-in of homogeneous events: multiple WebSocket channels, several sensors, retrying sources, or UI events from different widgets that feed one handler.
- Can merge combine a Flow<Int> with a Flow<String>?Not directly — merge requires the same element type. You would map each to a common type (e.g. a sealed Event) first, or use combine/zip which transform into a new type.
- Is the output order of merge guaranteed?No. It reflects arrival order across concurrently collected sources, so racing emissions interleave non-deterministically.
merge is several rivers flowing into one channel — the water mixes in whatever order it arrives, nothing is paired up.
saying these in an interview costs you the question
- Claiming merge pairs or transforms values
- Saying merge preserves a strict ordering across sources
- Thinking merge can join flows of different element types
- Believing merge collects sources sequentially rather than concurrently
- Assuming one source finishing completes the whole merged flow