Skip to content

Rationale · essay 00

Why Makoto

rationale.md · 85 lines · 4 min read

The thesis. Why one more systems language, when Rust, Go, Zig and the BEAM already exist.

“Systems language” usually means “language that touches the metal”: pointers, layout, syscalls. But there is a second reading, and it is the one Makoto starts from. A systems language is a language that recognizes itself as made of several subsystems (execution, types, memory, concurrency, errors), each with its own “colors”, and whose job is to manage the boundaries between them.

The thesis fits in three verbs: Rust leaks, Go fuses, Makoto separates.

  • Rust leaks. The realms bleed into one another. async does not stay in the execution realm: it colors the type system and escapes into every signature. Lifetimes infect functions that do not even touch the problem they solve. The result is that you spend your time undoing what leaked instead of composing. Too much coupling between subsystems.
  • Go fuses. There are no separate realms; there is one single system. It is simple while it fits, but extending forces you to touch everything, because there is no isolated realm to grow in (generics arrived years later, and they hurt). Absence of subsystems.
  • Makoto separates. Isolated realms, with neutral boundaries. The sin to avoid is the color of one realm staining another. When the color stays confined to its realm, the language gains three properties at once: the core stays sacred (no realm forces a change in another), the language is extensible by subsystem (a realm grows without touching the others), and a future realm enters without rewriting the ones that already exist. It is the bet in one sentence: subsystems that compose because they never stain each other.

The metric that decides whether a feature deserves to exist is the opt-in test: you only pay for what you summon. A concept is expensive not because of its internal complexity, but if those who do not use it still need to understand it. unsafe in Makoto is cheap because it lives in small islands, and those who do no FFI never see it. Lifetimes in Rust are expensive because they leak into every signature, so even those who write trivial code pay. The test filters: the language can be consistent without being simple, rich where you enter and invisible where you do not enter.

The four inspirations are not equal. Two are positive, two are counter-examples:

  • BEAM / Erlang (positive): the philosophy of isolated realms taken to concurrency, with processes that share nothing, supervision and let it crash. It is the largest structural inheritance (the concurrency section is the longest in the doc).
  • Zig (positive): the compiler as a tool and not magic, with comptime, allocators as interfaces and FFI that reads the header. And the separation MemorySource (where the bytes come from) versus @mm (which strategy governs them) is Zig’s decoupling taken one level further.
  • Rust (counter-example): it shows the cost of leaking. Makoto wants Rust’s memory safety guarantee without the borrow checker infecting everything.
  • Go (counter-example): it shows the cost of fusing. Makoto wants Go’s lightness without the impossibility of extending.
  • Why not “just use Rust”? Because Rust’s price is paid by everyone, always, and the opt-in test fails it. Rust’s memory safety is real, but it comes bound to a model (lifetimes, &T/&mut T) that colors the entire program. Makoto recovers the guarantee by another route (ch. 02).
  • Why not “just use Go”? Because “one single system” has nowhere to grow. The realms are missing.
  • Why not the BEAM (Elixir/Erlang)? Because the BEAM is interpreted/dynamic and does not descend to the metal; Makoto wants the BEAM’s resilience in a compiled, typed, systems language.

The beginner Rust programmer who has to understand lifetimes to write code that does not even touch them. The Go team that discovers, years into the project, that adding generics meant touching the base of the language. The Zig user who mixes PageAllocator/HeapAllocator/StackAllocator at the same level and loses the separation between “where the RAM comes from” and “how it is managed”. Each of these pains is a realm that leaked, or a realm that was missing.

Subsystems that compose because they never stain each other. A function signature says what it does, never how it runs. And you only pay for what you summon.

The separation has a named cost: some contagions are deliberately kept. unsafe is contagious (calling unsafe requires an unsafe context), but that is contract coloring, not implementation coloring. It informs you of a real danger, and, unlike async, it can be contained (any function that meets the preconditions absorbs the danger and exposes a safe interface on top). The language does not pretend the danger does not exist; it confines it. The name Makoto (誠, “truth”) points to exactly this: not to a subsystem, but to the entire philosophy.

Next: 01 · Philosophy