r/csharp • u/rust-cohle_ • 1h ago
Showcase C#'s rules for top-level statements turned out to be a great fit for a reactive notebook, so I built one
been working on something called Reverb, it's basically a notebook for C# where changing one cell automatically re-runs only the cells that depend on it.
the cool thing is that C# already handles a lot of the hard parts for us.
it's just a normal .cs file with // %% comments separating cells, and you run it with dotnet run.
one thing i found interesting is how top-level statements in C# make dependency ordering pretty straightforward. you can't declare the same variable twice, and you can't use a variable before declaring it. so the order of cells in the file is already a valid execution order. no need to build a separate dependency scheduler like reactive Python notebooks such as marimo have to.
there are still a few things that need to be checked though:
a cell can't assign to a variable declared in another cell.
anonymous types can't cross cell boundaries because the generated code needs to reference the type.
local functions were an interesting one. turns out C# lets you call a local function before it's declared, which breaks the whole file-order-is-dependency-order assumption. had to add a rule for that too.
for dependency tracking, i'm using Roslyn's SemanticModel.AnalyzeDataFlow on each cell's statements. it tells us which variables are coming from other cells and which ones are declared by the current cell.
each cell then gets compiled into a static method. inputs are read from a shared value store and outputs are written back to it.
also added #line directives so compiler errors and stack traces actually point to the right lines in the original file.
here's a small example:
// %% id=threshold
var threshold = Ui.Slider("Minimum order", min: 0, max: 1000, value: 400);
// %% id=summary
var big = orders.Where(o => o.Total >= threshold.Value).ToList();
big.Count.Dump("Orders above threshold");move the slider and only the summary cell runs again.
install it:
dotnet tool install -g Reverb.Notebooksit's open source (MIT):
https://github.com/muneeb-devp/reverb
would love to hear about any weird C# data flow edge cases i might have missed. especially things that could break the dependency tracking. always possible i've overlooked something :)

