Generate Kernels, Not More Code
2026-02-17
Spreadsheets, Reactive Cells, and the Substrates We Forgot to Build
I was a student writing APL for IBM Canada when VisiCalc hit the scene — the mother of all spreadsheets. VisiCalc was written in 6502 assembler. To most people, that’s a trivia factoid. To me, it’s the whole point.
A CPU is just a building material.
Most so-called programming languages are just ways of writing assembler with less potential for bugs. They are all “assembler” at heart, with the added bauble of “type-checking” built into the language instead of being — correctly — made into a stand-beside “linter” tool. We keep confusing the scaffolding for the building.
The Prolog Lesson
Prolog was originally written in ALGOL-W in 1972, then rewritten in FORTRAN in 1973, then assembler in 1974, and finally written in itself. The underlying operation of Prolog is very different from that of a stock CPU. But once they built the inferencing kernel — the core substrate that made unification and backtracking native operations — a whole new field of programming ensued. Relational programming didn’t come from adding features to existing languages. It came from building a new substrate and letting programmers think in terms natural to that substrate.
This is the pattern that matters: you don’t get new paradigms by decorating old ones. You get them by building new kernels.
What Spreadsheets Actually Are
A spreadsheet is a constraint-based system. You don’t tell it how to compute — you declare what depends on what, and the system figures out the propagation order. VisiCalc’s genius wasn’t the grid UI. It was the reactive dependency engine underneath.
And yet, when programmers try to build spreadsheet-like systems today, they reach for the wrong tools. They think about it as a flat plane of synchronous code — cells evaluated in some topologically sorted order, the whole thing re-executed on every change. This makes the problem harder than it needs to be.
Reactive Cells as Building Material
My background in embedded systems led me to Harel’s Statecharts (1986), which led me eventually to a practical system for writing programs using diagrams and asynchronous message passing — what I call PBP (Parts Based Programming, formerly “0D”). The core idea: nodes and arrows. You draw dependencies and pass pure messages between components. Programs become LEGO® blocks.
Looking at spreadsheets through this lens, the architecture becomes obvious:
Layer 0: Async reactive cells. Each cell is an independent component that can receive messages and emit updates. No global clock. No synchronous sweep. Just cells that react when poked.
Layer 1: A wiring layer. Something that connects cells to each other — the arrows between the nodes. When cell A changes, a message flows along a wire to cell B, which recalculates and maybe sends messages of its own.
Layer 2: A dependency scraper. A higher-level tool that looks at formulas (or constraints, or declarations) and automatically generates the wiring. The programmer doesn’t hand-draw every arrow — they declare relationships, and the system infers the topology.
This is “generate kernels” in action. You don’t write a spreadsheet engine as one monolithic program. You build a reactive substrate, then layer intelligence on top of it.
The Mistake We Keep Making
The mistake is thinking about the problem as synchronous computation that needs to be optimized. The reality is that a spreadsheet is a network of independent reactive agents that need to be wired together. The synchronous, flat-plane view is an accidental complexity we impose on ourselves by choosing the wrong substrate.
VisiCalc’s authors understood this intuitively — they built their reactive engine directly in 6502 assembler, choosing their own substrate rather than inheriting someone else’s assumptions. They generated their own kernel.
Every time we build something genuinely new — Prolog’s inference engine, VisiCalc’s dependency tracker, Harel’s statechart semantics — we do it by refusing to think in the terms our current tools impose on us. We build a new bottom layer. We generate a new kernel. Then we build upward from there.
The next time you find yourself wrestling with variable dependencies, propagation, and constraint management, ask yourself: am I writing more code, or am I building a new substrate? The answer determines whether you’re solving the problem or just rearranging it.
See Also
Email: ptcomputingsimplicity@gmail.com
Substack: paultarvydas.substack.com
Videos: https://www.youtube.com/@programmingsimplicity2980
Discord: https://discord.gg/65YZUh6Jpq
Leanpub: [WIP] https://leanpub.com/u/paul-tarvydas
Twitter: @paul_tarvydas
Bluesky: @paultarvydas.bsky.social
Mastodon: @paultarvydas
(earlier) Blog: guitarvydas.github.io
References: https://guitarvydas.github.io/2024/01/06/References.html

