Skip to main content

Terminals

the terminals

Stages are inert; the terminal is where everything happens. When you write .sum or .find(p) or .run, that call (an inline macro: code that runs inside the compiler, guaranteed-inlined at the call site, rewriting the typed syntax tree) receives the whole chain as a syntax tree and compiles it into one loop. Which terminals a pipeline has is decided per source shape; Integrating covers that machinery. This page is what the terminals do.

The families

The familiar collections surface is all here, each in one fused pass:

buildrun · toList · toVector · toSeq · toSet · toArray · toMap · to(Factory) · mkString

aggregatefoldLeft · fold · sum · product · count · count(p) · size · length · agg · aggTo

searchfind · exists · forall · contains · isEmpty · nonEmpty · head · headOption · indexWhere · indexOf · collectFirst

reducereduce · reduceLeft · min · max · minBy · maxBy · …Option variants · last · lastOption

group / rankgroupReduceBy · groupReduce · groupCount · groupSum · groupBy · groupMapReduce · topN · bottomN · topNBy · bottomNBy

multi-outputpartition · span · unzip · sliding · plan

Four of them have their lowerings shown here, because they do things the standard library can't.

Search terminals stop the machine. find plants a done-flag that every loop level carries, across sources and flatMap nesting alike, so the traversal ends as soon as the answer exists:

you write

loading source…

the macro emits

loading source…

agg answers several questions in one pass. Needing sum, count, and max together is normally three traversals or a boxing tuple-fold. Here each aggregate rides its own unboxed accumulator and the loop body is just N statements:

you write

loading source…

the macro emits

loading source…

aggTo lands the answers in your own type. Same machine, but the last line of the lowering is Summary.apply(total, n, top) instead of a tuple you unpack:

you write

loading source…

the macro emits

loading source…

groupSum folds groups without boxing. groupBy builds a Map[K, List[A]], pure overhead when you only wanted an aggregate per key. groupReduceBy (and its groupSum/groupCount spellings) folds each group as elements stream past into a primitive-keyed open-addressing table: Int keys and Int/Long/Double accumulators stay unboxed in the hot loop, and boxing happens exactly once per key, at the final O(#keys) materialization:

you write

loading source…

the macro emits

loading source…

The ranking family exists because "top ten by score" should not cost a sort: topNBy(n)(key) keeps a bounded size-n heap inside the pass (O(N log n) time, O(n) memory, best-first):

you write

loading source…

the macro emits

loading source…