Byte for Byte

With three bugs fixed, the two outputs were finally worth comparing: the program compiled by the reference compiler, and the same program compiled by the compiler that had been compiled by itself. They were identical — not close, not equivalent, but the same bytes in the same order — and running either produced the right answer. That is the bootstrap fixpoint, and it is the strongest thing a language can say about itself. This is where the map, for now, ends: not with a promise, but with a compiler that has looked in the mirror and found itself unchanged.

mereself-hostingbootstrapfixpointlanguage-design

The test had been the same from the beginning of this part, and now it could finally be run in full. Take a program. Compile it with the reference compiler — the one running under the interpreter, trusted, correct — and keep the output. Then compile the same program with the compiler that had been compiled by itself into a WebAssembly binary, now running as that binary, and keep its output too. Lay the two side by side. The question the whole part had been circling was whether they would match.

Identical

They did — and not in the loose sense that word sometimes carries. The two outputs were the same bytes in the same order, indistinguishable down to the last character, a difference of exactly zero. And it was not a match of empty things: each was a substantial program, thousands of lines of generated code, agreeing completely. Then the last check, the one that turns a curiosity into a fact: the output was itself run, and it produced the right answer. So the chain held at every link — the compiler, the compiler compiled by itself, and the program that second compiler produced, all three correct and the middle two identical. That is the bootstrap fixpoint. A compiler that, compiled by itself and run as a binary, reproduces its own reference output exactly is not merely self-hosting in the weak sense of being able to emit itself. It is self-hosting in the strong sense: the copy is faithful, and you can prove it, byte for byte.

Why the strong sense is the one that counts

It is worth being clear about why this is the claim worth having, because the weaker one is easy to mistake for it. A compiler that emits a valid binary of itself has shown that its code generator can handle its own source — a real result, but a structural one, about shapes the validator will accept. It says nothing about whether that binary, run, behaves as the compiler behaves. The strong claim closes exactly that gap. It says the emitted compiler is not just well-formed but correct as a compiler, faithful enough that its output cannot be told from the original’s. Everything in this part lived in the space between those two claims — the overflow, the missing tail call, the three bugs that only a mirror could show — and none of it was visible until the language was made to stand entirely on itself, with no interpreter’s generous stack and no type inferencer’s ambient knowledge holding it up. The fixpoint is the moment that support is fully removed and the language does not fall.

A regression test, so it stays true

A fact proven once is a fact that can quietly stop being true. So the fixpoint was written into the test suite itself: on every run, the suite compiles a program with the reference compiler and with the self-compiled compiler and asserts that the two outputs are byte-identical. The proof is no longer a thing that happened; it is a property that is checked, and any future change that breaks the faithful copy will fail loudly instead of drifting silently. The milestone became a release, and the release carried what this part had built: the guaranteed tail call, the three self-compilation fixes, and the check that guards them all. The strongest claim the language can make is now the cheapest to keep.

What the whole thing was about

This is the edge of the map, and a good place to look back at the ground crossed to reach it. Ten parts, and one method under all of them. A hard question was narrowed on paper into precise pieces, tried in a small experiment before being trusted, and then dogfooded against something real until its rough edges showed. When a new problem appeared, the first move was to lean on machinery already built rather than invent more — the memory model that went native, the compile-time specialisation that grew a family, the tail-position bit threaded through one construct at a time. Restraint was an act with evidence behind it: locks not built, an LLVM backend not invested in, features left named on the horizon rather than rushed. And the guarantees were held to honestly in both directions — never claiming a soundness that wasn’t there, never hiding an edge that was.

The bootstrap fixpoint is a fitting place to pause because it is that whole method turned on the language itself. For most of the series the language was the thing doing the testing, the tool that built the web apps and the CLIs and the documentation and found their pains. At the fixpoint it becomes the thing tested — handed its own source, asked to reproduce itself exactly, and made to reveal, under that most demanding of loads, the defects nothing gentler had ever surfaced. It passed. A language that started as a philosophy and a minimal core has compiled itself, faithfully, and can prove it does. The map still has edges, and development will keep redrawing them. But this is a real summit, not a false one — the compiler has looked in the mirror and found itself unchanged — and it is where this account of the building ends.

← Back to Mere: Building a Language