Running balance from a deposit feed
Requirement
An account opens at zero and receives seven movements — deposits positive, withdrawals negative. Print the balance after each movement, one line per step. The data is in the code; both versions must print the lines shown under Expected output.
Expected output
Balance: 250 Balance: 170 Balance: 290 Balance: 250 Balance: 750 Balance: 430 Balance: 520
Side by side
RxDart
FxDart
Why they differ
They barely do. Running state is a fold with its intermediate steps
exposed, and both libraries call that fold scan — RxDart
as a stream transformer, FxDart as a lazy operator ported from the
same Rx lineage. One accumulation per movement, in order, on both
sides.
The visible differences are cadence details, not model differences.
RxDart's scan takes a seed and emits one value per
event (its accumulator also receives an index); FxDart's seeded
scan follows FxTS and yields the seed itself first, so
the panel uses the unseeded scan1 — for a balance that
opens at zero, each partial sum is the balance, and the two
cadences line up exactly. Beyond that, the only residue is delivery:
the stream version collects through an async main, the
pull version is one synchronous chain. A fair tie — both sides say
the requirement with a single operator.
Benchmark
N = 100
Time Tie
Peak memory Tie
N = 1,000,000
Time FxDart wins
Peak memory RxDart wins
Bars are medians of repeated timed iterations in fresh processes per side (small N is batched for timer resolution). Sides within 5% of each other — or within 0.6 ms, a difference no person can perceive — count as a tie; close relative races are re-measured up to 5 runs. In an app, anything under a few milliseconds is invisible to the user regardless of which bar is shorter. Memory is peak process RSS. The Dart VM and the dataset are identical on both sides, so the difference between the two bars is what the pipeline itself holds onto.