mergeScan, switchScan & expandEach
Fold each event into shared state through an inner stream — merge them, switch them, or walk a tree. The seed is not emitted.
Lecture
FxEvents.scan emits the seed first, then each running
accumulation — the pull-layer convention, same as
scan.
mergeScan and switchScan do
not. The seed is only the starting accumulator,
never an event. That matches Rx, and it is the thing that surprises
people coming from FxEvents.scan: an empty source
closes empty.
mergeScan(seed, acc) folds each event by opening
accumulator(state, value) as an inner stream. Every
inner emission becomes the new state and is forwarded. With
concurrent: n at most n inners run at a time
and the rest wait in a queue; they share one state variable — the
latest inner emission wins. Null concurrent is
unlimited. The result closes when the source has closed and every
inner has finished.
switchScan is the cancelling sibling: a new source
value cancels the previous inner mid-flight, and
the latest inner emission (if any) is the state handed to the next
accumulator call. After the source closes, the current inner is
allowed to finish.
expandEach is Rx's expand, renamed
because the pull layer already uses that word for iterable
flatMap. It emits every
source value, then recursively flattens project of
that value — and of every value project itself emits —
breadth-first. A project that never returns an empty
stream will not terminate. fxdart events layer, after Rx's
mergeScan, switchScan and
expand.
Demo 1 · mergeScan — the seed stays silent
Demo 2 · switchScan — newer cancels
Try it yourself
Exercise: expandEach, a finite tree 0 → 1 → 2.