The FBP Language/ Streams

Streams

Streams

Two arrows turn a single packet into a batch of packets, and back again. They are exact inverses:

  • => splits — one array packet becomes one delivery per element.
  • >= collects — a stream of packets becomes one array when the batch closes.

=> — the cyclic feed

["a", "b", "c"] => in Echo(stream/echo)

The => arrow marks the target port as cyclic. When an array arrives, the runtime splits it and delivers one element at a time: Echo runs three times, receiving "a", then "b", then "c".

The split is unconditional — a flat array feeds each element to a scalar port separately, while an array-of-arrays feeds an array port one sub-array per delivery. A non-array value fails loudly rather than being silently dropped.

=> is the loop/recurrence feed: feeding a node's output back through => makes it process a stream in bounded steps instead of all at once.

>= — the collect

Echo out >= in Collect(console/log)

The >= arrow marks the source port as collecting. Packets that cross the link are buffered, and when the batch closes the whole stream is flushed as one array packet. Collect receives ["a", "b", "c"] in a single run.

Collecting is the inverse of splitting: whatever was deconstructed by => can be reconstructed by >=, without knowing how many items there were.

Batches and end-of-stream

A batch is a set of deliveries that the runtime knows has a beginning and an end. The end of a batch is called end-of-stream (EOS), and it is what lets a collector know when to flush.

The rule to remember:

A finite stream requires a batch boundary. A cyclic feed (=>) opens a batch, delivers each element, and closes it. A plain (non-cyclic) IIP writes one packet and never closes a batch — so a >= collector fed by a plain link never flushes until the run ends.

That is why the three arrows work together:

["a", "b", "c"] => in Echo(stream/echo)
Echo out >= in Collect(console/log)

The => is what makes the stream finite: it closes the batch, the close relays through Echo, and the collector flushes on it.

A >= wire fed by a plain -> source still materializes — the batch closes when the run completes, so a single packet collects to a list of one:

'just one' -> in Dummy(utils/dummy)
Dummy out >= in Collect(console/log)   # Collect receives ["just one"] when the run ends

What streams make possible

  • Streaming nodes consume the per-packet feed directly. A streaming: true node with a bare fn runs once per packet — the runtime owns the loop. See the streaming reference.
  • Materializing a stream into a plain node is exactly what >= is for: it is a legitimate stream terminator that hands a buffering consumer the whole list at once.

The =>/>= pair and the batch/EOS relay are implemented as port behaviors; the details of the mechanism are in the runtime.

Edit this page