Skip to content

Projections

Preview — Ranvier is pre-release; its APIs may change.

Projections keep keyed, per-row reactive state over a collection source. Selectors (Lookup) track, per key, whether that key matches a source value. See Benchmarks for configuration, environment and caveats.

ProjectionBenchmarks

A projection over Items rows (8, 64 or 512), observed by one effect so that the projection stays scheduled.

MethodWhat it measures
ReadRowA tracked read of one cached row.
EditOneItemA write that changes the value of the first row, re-running that row's effect.
ReorderA write of the same keys and values in reverse order: the key order changes and every row keeps its value.

Recorded 2026-09-28. Source: Ranvier.Benchmarks.Projections.ProjectionBenchmarks at commit d87920f.

MethodItemsMeanErrorStdDevOp/sGen0Gen1Allocated
ReadRow86.184 ns0.0715 ns0.0669 ns161,707,225.4---
EditOneItem8214.629 ns2.3013 ns2.1527 ns4,659,197.70.0057-96 B
Reorder8183.185 ns2.5630 ns2.1403 ns5,458,957.00.0210-352 B
ReadRow646.013 ns0.0744 ns0.0696 ns166,315,149.2---
EditOneItem64925.895 ns11.0672 ns10.3522 ns1,080,035.80.0057-96 B
Reorder641,140.921 ns10.3918 ns9.2121 ns876,485.00.1411-2368 B
ReadRow5126.005 ns0.0735 ns0.0688 ns166,522,611.8---
EditOneItem5126,653.607 ns45.0946 ns35.2069 ns150,294.4--96 B
Reorder5128,307.363 ns104.3172 ns92.4745 ns120,375.11.09860.091618496 B

Key churn and key readers

A key reader (Projection.NewKeyReader) reports the keys added, removed and moved since its previous read. These cases measure a write that removes one key and adds another, and what a reader adds to it.

ProjectionBenchmarks.ChurnOneKey runs on the fixture above's Items: one effect observes each row except the last, and one observes Keys.

MethodWhat it measures
ChurnOneKeyA write removing the source's last key and adding a key the source has never held, with no key reader.

DeltaReaderChurnBenchmarks is ChurnOneKey with Readers key readers (1 or 4), each read by its own effect after every write, at Items 8, 64 or 512.

MethodWhat it measures
ChurnOneKeyThe same write, then one read per reader. The difference from ProjectionBenchmarks.ChurnOneKey is the readers' cost.

DeltaReaderBenchmarks compares two ways of finding one change. The source toggles key Items / 2 out and back in on every write, at Items 64, 512 or 10 000.

MethodWhat it measures
SetDiffAfterOneRemovalBaseline. The toggle, then a set difference of the previous and current Keys: linear in Items.
ReadAfterOneRemovalThe toggle, then the change read from the key reader.
ReadIdleA read of the key reader with nothing changed since the previous read.

The counter scenario project-churn measures the same write over 1000 rows, with no key reader and with one read by an effect. Figures are retired instructions per operation at commit e13f159, .NET 10 with tiered compilation and PGO off (see Instruction counts):

Variantinstr/opbytes/opLibrary counters/op
No key reader539,7754,592SignalsCreated 1, MemosCreated 1, EffectRuns 1, Flushes 1
One key reader541,2764,992SignalsCreated 1, MemosCreated 1, EffectRuns 2, Flushes 1

A key reader adds about 1,500 instructions and 400 bytes to the churn pass, about 0.3 %. The BenchmarkDotNet cases, including DeltaReaderBenchmarks and four readers, are in the suite for local runs (dotnet run --project bench/Ranvier.Benchmarks -c Release -- --filter "*ChurnOneKey*" "*DeltaReader*") and have no published figure yet. The full report is e13f159.md.

LookupBenchmarks

A selector created with createSelector, whose key 7 loses its last observer and is read again before the next transition. Each case should reuse the key's cell; a regression would rebuild it.

MethodWhat it measures
RemountKeyMounting and disposing the only reader of a key.
ReadAheadOfGetRe-running a reader that inserts or drops a read ahead of its Get.
UntrackedGetAn untracked read of an unobserved key.

Recorded 2026-09-28. Source: Ranvier.Benchmarks.Projections.LookupBenchmarks at commit d87920f.

MethodMeanErrorStdDevOp/sGen0Allocated
RemountKey101.88 ns1.721 ns1.525 ns9,815,568.70.0257432 B
ReadAheadOfGet54.37 ns0.434 ns0.406 ns18,392,960.70.001424 B
UntrackedGet21.15 ns0.170 ns0.159 ns47,272,722.80.001424 B
Edit this page