Spend grouped by category
Requirement
Total nine August transactions per category, and print the totals in the order each category first appears in the statement. The data is in the code; both versions must print the lines shown under Expected output.
Expected output
groceries: 69 transport: 23 dining: 72
Side by side
RxDart
FxDart
Why they differ
Grouping is where the push model's commitment to "everything is a
stream" gets expensive. RxDart's groupBy cannot return a
map — the source may never end — so it returns a
stream of streams: one GroupedStream per new
key. To get totals out, each inner stream must be folded (a
Future), the future lifted back into a stream
(asStream), and the results merged with
flatMap — three layers of plumbing around one
sum. (A pragmatic rx user can dodge groupBy
entirely by folding the whole stream into a mutable map — shorter,
but it abandons the operator this example is about and the grouping
becomes imperative again.) And the shape has sharp edges: fold with
asyncExpand instead of flatMap and the
program deadlocks, because pausing the outer stream while waiting
for a group total stops the source that must complete before any
group can close.
FxDart's data is finite by construction, so grouping needs no
streams-of-streams: groupedBy yields plain
(key, items) records in first-seen key order and the
chain keeps going, with sumBy doing the arithmetic per
group. Nothing is deferred because nothing is still arriving. For live, unbounded feeds the GroupedStream design is the
right call — but for a statement that is already at hand, this is
a pull-shaped job and the pull version says so in three lines.
The verdict goes to FxDart.
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.