AI authored to showcase ironpad capabilities.
Every cell in a notebook can call into a common shared module. There are two ways to put code there, and this notebook uses both kinds of visibility deliberately:
shared.rs and every cell can call them as shared::.... Use them when the shared code is part of the story.Below, two amber shared cells define format_greeting and fibonacci, and the ordinary cells after them consume both. Along the way: what shared cells do at compile time, the assembly order, and one sharp edge around feature detection.
The notebook-level shared source came first, and it has one failure mode: everything you share disappears into a single collapsed blob at the bottom of the page. Fine for plumbing; terrible for teaching. A notebook that says "call shared::simulate_step" while hiding simulate_step in an appendix pulls the reader away from the argument right when the code matters most.
Shared cells fix that. When a helper is load-bearing for the narrative, promote it to a shared cell and it sits inline, amber, right where the story needs it. format_greeting below is 3 lines; fibonacci is 15. Hiding either would cost more comprehension than it saves in scroll height.
Three rules pin down the semantics, and all three fall out of one fact: a shared cell is source text, not an execution unit.
shared.rs and compiled into every other cell.cell0, cell1, ...), and every cell, shared or markdown included, occupies one index in that numbering. A shared cell's slot is simply empty. The flip side: inserting any cell above a producer shifts the indices its consumers reference, so add narrative cells below the piping chains they discuss.For a mental model: shared cells are header files that happen to live in the essay. Now the consumers.
The notebook builds one shared.rs, and the recipe is deterministic: the notebook-level shared source first, then every shared cell top to bottom in notebook order, joined by blank lines. This notebook has no notebook-level shared source, so the generated file is exactly the two amber cells:
// shared.rs, as generated for this notebook
pub fn format_greeting(name: &str) -> String { /* amber cell 1 */ }
pub fn fibonacci(n: u64) -> u64 { /* amber cell 2 */ }
shared::.shared.rs.A shared_cargo_toml rides along too (here, a small [profile.release] tweak); its dependencies merge into every cell's build the same way.
The next cell leans on shared::fibonacci harder: consecutive Fibonacci ratios converge on the golden ratio, 1.618, within 10 terms.
This is the sharp edge. ironpad picks heavyweight build features by substring scanning the text it compiles: the cell's own source plus the entire shared source. std::simd or core::simd anywhere in that text opts the cell into SIMD codegen; rayon in the merged dependencies triggers an atomics build with a full std rebuild; the autodiff intrinsics pull in the Enzyme toolchain.
Because shared text is appended to every cell's compile input, one trigger substring in a shared cell opts every cell in the notebook in. The scan is textual, so a comment counts:
// A shared cell containing only this comment:
// "We could vectorize this with std::simd later."
// ...now builds EVERY cell with -C target-feature=+simd128.
That one is mostly harmless (simd128 is cheap and universal in modern browsers); the same slip with rayon in shared_cargo_toml forces a far slower -Zbuild-std atomics rebuild on every cell. The rule: keep heavyweight triggers out of shared code; if one cell needs SIMD, mention SIMD in that cell. Markdown is never scanned, which is why this cell gets to say all of this freely.
The mechanics are identical (same module, same cache behavior, same feature-detection blast radius), so the choice is purely editorial:
Either way, one keystroke in shared code recompiles the whole notebook, so shared code is the right home for code that has stopped changing. Draft in a normal cell; promote once it settles.
One last cell pulls both helpers together.