A default line for an empty report
Requirement
A spending report filters this month's transactions down to the
travel category — and there aren't any. An empty report
should not print nothing: it should print a single
no travel spending line instead. The data is in the code;
both versions must print the line shown under Expected output.
Expected output
no travel spending recorded in August
Side by side
RxDart
FxDart
Why they differ
Hardly at all — and in the same place. "Emptiness needs a fallback"
is a problem both models
hit in exactly the same place — a downstream stage cannot tell
filtered to nothing from never had anything unless
the pipeline says what to emit in that case — and both libraries
answer with one operator. RxDart's defaultIfEmpty injects
the default when the source completes without an event; FxDart's
defaultIfEmpty (openly borrowed from the
Rx vocabulary, with ifEmpty(() => fallback) as the
lazy whole-iterable form) yields it when the first pull finds
nothing.
The residual difference is the usual one in this Part: the stream version has to know it is empty by waiting for completion, so the whole program goes async over a fixed list, while the pull version discovers emptiness synchronously on the first demand. That cost is real but small here, and the operator parity is the story — a genuine tie, and a nice example of the two libraries trading ideas rather than competing.
Benchmark
N = 100
Time Tie
Peak memory Tie
N = 1,000,000
Time FxDart wins
Peak memory Tie
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.