Reactive and Dataflow Programming

Reactive programming models values or streams that change over time and allows dependent computations to respond to those changes.

13.1 Reactive programming

Reactive programming models values or streams that change over time and allows dependent computations to respond to those changes. It is often used for UIs, event streams, telemetry, and asynchronous data pipelines.

13.2 Observable streams

Conceptual TypeScript-style example using a reactive library:

The stream waits briefly after typing, ignores consecutive duplicate values, and switches to the latest search operation. Exact imports and types depend on the library version. Cancellation behavior of the underlying network request depends on the observable and transport implementation.

// Illustrative RxJS-style API.
const searchResults$ = searchInput$
  .pipe(
    debounceTime(250),
    distinctUntilChanged(),
    switchMap(query => searchCourses(query))
  );

13.3 Reactive operators

Common operator families:

Transform: map Filter: filter Combine: combineLatest, zip, merge

Flatten: mergeMap, concatMap, switchMap, exhaustMap Recover: catchError or equivalent

Time: debounce, throttle, delay, timeout Lifecycle: cancellation, completion, disposal

Operators have different concurrency and ordering semantics. Choose based on whether every event must be processed, only the latest matters, or events must be serialized.

13.4 Backpressure

Backpressure coordinates producer and consumer rates. Without it, a fast producer can create unbounded queues and memory use. Strategies include bounded buffering, dropping or sampling events, pausing upstream production, and applying demand signals.

13.5 Dataflow programming

In dataflow systems, values move along edges in a dependency graph. A node runs when its inputs are available or change. This model appears in visual programming, spreadsheets, build systems, hardware descriptions, and stream processing.

Try it: a dataflow graph Edit an input cell and watch the change propagate through the dependency graph, like a spreadsheet. The explorer recomputes only the cells that depend on the edited one, in dependency (topological) order, and lists the order it used.

13.6 Functional reactive programming (FRP)

FRP combines functional composition with time-varying values or event streams. Different FRP systems define behaviors and events differently; the term covers a family of approaches rather than one universal API.

13.7 Common pitfalls

Stale async responses overwriting newer state Duplicate side effects Accidental concurrent execution

Error streams that terminate unexpectedly Confusing cold and hot observables Hidden scheduling behavior

Exercise

Build a live course-search feature. Compare ordinary event handlers, async/await, and a reactive stream. Test fast typing, slow responses, cancellation, and empty results.

Quiz

? Which flattening operator keeps only the latest inner operation, cancelling the previous one?
+ switchMap :: It switches to the newest inner stream — ideal for search-as-you-type.
- concatMap :: It serialises inner streams; none are cancelled.
- mergeMap :: It runs inner streams concurrently.
- exhaustMap :: It ignores new values while one is running.

? In a dataflow system, when does a node run?
+ When its inputs are available or change. :: Dependencies drive execution.
- In source-code order. :: Order comes from the dependency graph.
- Only once at start-up. :: Nodes re-run when inputs change.
- When a timer fires. :: Time is not the trigger in pure dataflow.

? Which are common reactive pitfalls? (select all that apply)
+ Leaked subscriptions :: Forgotten subscriptions keep running.
+ Stale async responses overwriting newer state :: A slow old response can arrive last.
+ Unbounded buffering :: A fast producer can exhaust memory.
- Values that never change :: Constant values are harmless.