Drop the nulls, keep the values
Requirement
A battery monitor produced nine voltage samples, three of which the
sensor dropped (null). Discard the failures, print each
surviving sample formatted to one decimal, then report how many were
dropped. The data is in the code; both versions must print the lines
shown under Expected output.
Expected output
3.4 V 3.9 V 4.1 V 3.7 V 4.4 V 4.0 V Dropped 3 empty samples
Side by side
RxDart
FxDart
Why they differ
whereNotNull is compact — the same
operator wearing each library's naming convention. Both do the thing
that matters beyond filtering: they narrow the static
type, turning a double? element type into
double, so the toStringAsFixed call
downstream needs no null checks and no !. Filter and
promote in one word, on both sides.
So the verdict is a tie on vocabulary — and the honest remainder is
only the delivery model. The stream version lifts a list it already
holds into a Stream and awaits the collection back out;
the pull version finishes before the stream version's first
await would have run. On a nine-element fixed list that
overhead is small enough to shrug at, which is exactly the
difference between this example and the verdict-carrying aggregation
in Total the valid even amounts: here the point is that the
two libraries agree, right down to the type promotion.
Benchmark
N = 100
Time Tie
Peak memory Tie
N = 1,000,000
Time FxDart wins
Peak memory FxDart 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.