Table of Contents

Denotational semantics

SodaFlow implements the denotational semantics of Sodium, unchanged.

That is a stronger claim than "it behaves similarly." Sodium is one of the few FRP libraries with a written formal specification: every primitive has a precise mathematical meaning, independent of any implementation. Stephen Blackheath wrote that specification, along with an executable reference implementation in Haskell. SodaFlow inherits the model and is tested against it.

Why this matters

Most reactive libraries define their behavior by what the code happens to do. Edge cases — simultaneous events, a stream that feeds itself, a switch that changes the graph mid-transaction — get whatever the implementation gives you, and the answer can change between releases.

A denotational semantics removes that ambiguity. Each primitive is a function over a timeline of occurrences, so questions like "if two streams fire in the same transaction, what does Merge produce?" have an answer derived from the specification rather than from reading the source. When SodaFlow and the specification disagree, SodaFlow is wrong.

This is also what makes the guarantees in Transactions and Switch trustworthy rather than aspirational.

The specification

The paper and its executable Haskell reference are vendored in this repository under denotational/, with their full history. The links below point at the canonical upstream copies:

In this repository Canonical copy
Paper denotational/Denotational Semantics of Sodium - 1.1.pdf Denotational Semantics of Sodium 1.1
Executable reference denotational/sodium.hs sodium.hs — the semantics as runnable HUnit cases
Core definitions denotational/Reactive/Sodium/Denotational.hs Denotational.hs

That material is Copyright © 2015 Stephen Blackheath and is licensed separately from the rest of SodaFlow — see denotational/LICENSE and the NOTICE file. It is included unmodified, and it describes Sodium; the naming inside it is deliberately left alone.

How conformance is checked

The semantics are not just cited, they are executed. DenotationalSemanticsTests transcribes the Haskell reference cases into both language surfaces — the same cases in each, case for case — and asserts SodaFlow produces the specified occurrences:

C# src/CSharp/SodaFlow.Tests/DenotationalSemanticsTests.cs
F# src/FSharp/SodaFlow.FSharp.Tests/DenotationalSemanticsTests.fs

They cover Never, MapS, Snapshot, Merge, Filter, SwitchS, Updates, Split, Constant, Hold, MapC, Apply and Sample — the primitives the paper defines — plus the .NET additions Value, ListenC, ConstantLazy, SwitchC and SampleLazy.

Each test drives a simulated timeline: streams are given fixed occurrences at integer times, the transaction at each time is run, and the observed output list is compared against the value the specification requires. Test_Merge_TestCase, for instance, pins down exactly what simultaneous occurrences produce — the case most libraries leave undefined.

Reading further

The paper is short and worth reading directly. For the informal treatment of the same model, Blackheath and Jones' Functional Reactive Programming (Manning) is the best reference both for the Sodium basics SodaFlow inherits and for Functional Reactive Programming in general.