A Singleton Is an Abstract Event
This continues the series answering David Barbour’s questions about Koru, and it leans on a claim made in full in Libraries, Not Keywords: that in Koru the line between “language feature” and “library” mostly doesn’t exist. His fifth point is where that pays off cleanly.
His point, restated:
An explicit notion of singletons — or, equivalently, content-addressed resources — is extremely convenient for modeling shared structure. You shouldn’t have to pre-define subroutines, libraries, or
.rodata. Generate them exactly once, upon demand.
There are two halves in there, and Koru answers them differently — one cleanly, one honestly-partial. Let’s take them in order.
A singleton is an abstract event with one implementation
Start from what a singleton is: there should be exactly one thing satisfying a given shape. Koru has a direct word for “a shape with one satisfying implementation” — it’s an abstract event.
An abstract event declares a contract — these inputs, that output — and leaves the implementation open. Exactly one implementation fills it. The whole Koru compiler is built this way: the pipeline orchestrator is an abstract event,
~[comptime|abstract] pub event coordinate { program_ast: *const Program, allocator: Allocator } with one default implementation that you can override. So is frontend, analysis, emission — each an abstract event with a single satisfying impl.
So compiler:coordinate is, quite literally, a singleton: one implementation
returning the emitted code for the program’s shape. And the way it gets
specialized for a particular shape — generated for exactly this program and no
other — is monomorphization. The abstract event is the shape; the implementation
is the one thing that fills it; monomorphization is “generate it for this case,
on demand.” That is David’s singleton, mechanism for mechanism, with no keyword
spent on it.
Resources are code generation, and const is the proof
The other half of his point is about data — shared structure, the bytes a
language usually parks in .rodata. Koru generates data the way it generates
everything else: with its metaprogramming layer. And the proof is sitting in
plain sight, in the place you’d least expect it — const.
const is a keyword. You write it like one. But it is implemented entirely
in user-space: it lives in koru_std/declarations.kz, declared [keyword|declaration],
and its implementation is a template proc over a source block — one per target:
~[keyword|declaration] pub event const { source: Source }
~proc const|template|zig { … }
~proc const|template|js { … } That split is the whole point. The keyword is real surface syntax; the meaning is library code. So whatever a construct for “data of any shape” needs — a richer
const, a typed resource — can be built in user-space without touching the
compiler. A const is generated by running its template, monomorphized per
target: the Zig build gets one specialization, the JavaScript build another. It
isn’t a built-in; it’s the metaprogramming substrate applied to the simplest
possible case. Its tests even live under the stdlib, not the core language:
Underneath const are the primitives a std/data-style resource would stand on,
and it’s worth being precise about them, because const only needs the easy one. Templates — what const uses — are the convenient subset of Koru’s
metaprogramming: site-local instantiation, ideal for generating a structure on
demand. They are not the whole story. Above them sits the transform, which can walk
and rewrite the entire program; templates deliberately can’t reach that far. And source blocks embed verbatim bytes — the actual .rodata-shaped thing. But
even transform isn’t the outermost lever: a transform runs as a compiler pass,
and the passes themselves live in user-space — you can override them or remove
them. The true outermost construct is rewriting the compiler pipeline of the
program that is currently compiling. So a real resource library would reach for
templates where they suffice, transforms where it needs full-program traversal,
and — at the limit — a custom pass in the pipeline itself.
So “generate them exactly once, upon demand, without pre-defining .rodata” is
not a request Koru has to grow a feature to meet. It already generates resources
on demand, through its metaprogramming layer, specialized once per shape. const is what that looks like at its smallest — and the smallest case is exactly where a
template suffices.
The honest seam — and where std/data comes in
Here is the part we won’t overclaim. David offered his point two ways: explicit singletons, or content-addressed resources. We answer the singleton framing directly. The content-addressed framing — deduplicate identical resources by their content, so the same structure is generated once no matter how many places ask for it — we only get implicitly, and from underneath: the Zig backend’s build cache is content-addressed, so byte-identical generated code collapses to one. That’s real, but it’s inherited, not named. Koru doesn’t expose a first-class “content-addressed resource” you can reach for.
The honest way to close that gap is, of course, a library. A std/data module —
not built yet, a proposal — would make content-addressed resources an explicit,
nameable thing, built on the same substrate: the metaprogramming layer (templates
where they suffice, transforms where it needs full-program reach), source blocks
for the bytes, monomorphization to do it once per shape. That keeps
the answer consistent with everything else in this series: when Koru needs a new
capability, the question is never “what keyword,” it’s “what library, on which
primitive.”
So, point five, answered without a single new piece of grammar: a singleton is an
abstract event with one implementation; a resource is code generation; and the
content-addressed flavor you’d want made explicit is a std/data library we’d
build on the primitives that are already here. Not a feature. A library — like
almost everything in Koru that feels like a feature.