Governed Metaprogramming
Governed Metaprogramming
Section titled “Governed Metaprogramming”Janus is the first language where compile-time evaluation is governed by the same capability system as runtime. The profile ladder doesn’t just restrict which APIs you can call — it restricts what the compiler itself is allowed to do on your behalf.
That is Mechanism over Policy applied to the compiler.
The Three-Layer Architecture
Section titled “The Three-Layer Architecture”No other systems language has attempted a unified comptime design with this structure:
Layer 1 — comptime do...end Blocks
Section titled “Layer 1 — comptime do...end Blocks”First-class compile-time evaluation with an actual ComptimeEvaluator backed by resource limits. This is not “the compiler happens to fold constants.” It is an explicit, bounded interpreter that runs your code at compile time and tells you when you’ve exceeded its budget.
const TABLE = comptime do var t: [256]u8 = undefined inline for 0..256 |i| do t[i] = compute_entry(i) end tendThe evaluator enforces hard limits: 1,000,000 steps, 256 MB memory, 1,000 recursion depth. Exceed any limit and you get a diagnostic — not a frozen terminal.
Layer 2 — The $ Meta-Sigil
Section titled “Layer 2 — The $ Meta-Sigil”$size_of, $align_of, $type_info. The $ sigil screams this is the compiler talking in a way that is visually distinct from runtime code. No ambiguity. No Zig-style @ that collides with 47 other things.
if comptime $is_integral(T) do optimized_int_path()else generic_path()endThe set is deliberately small. Most operations that Zig hides behind @builtins are regular library calls in Janus.
Layer 3 — Profile Gating
Section titled “Layer 3 — Profile Gating”:core gets the basics — checked arithmetic, $size_of, $align_of. :service unlocks introspection via $type_info, $fields, $has_field. :sovereign gets comptime allocation.
The profile ladder constrains the evaluator, not just the language surface. A :core program cannot accidentally depend on type introspection. A :service program cannot allocate memory at compile time. Capability escalation is explicit, visible, and auditable.
That third layer is what makes this sovereign. Nobody else has it.
The Competition
Section titled “The Competition”| Dimension | Go | Rust | Zig | Janus |
|---|---|---|---|---|
| Comptime model | None. go generate is a shell script with lipstick. | const fn + proc macros (two separate systems) | comptime keyword; same language at compile time | comptime do...end blocks with bounded evaluator |
| Type introspection | reflect package (runtime only) | Proc macros operate on token streams, not types | @typeInfo returns comptime struct | $type_info via profile-gated capability |
| Code generation | go generate (external tooling) | Proc macros (separate crate, separate compilation model) | Inline comptime; inline for / inline while | inline for / inline switch; same syntax, same semantics |
| Resource limits | N/A | Const eval has recursion limits (bolted on) | None. Comptime can loop forever. | Explicit resource budgets with diagnostics |
| Checked arithmetic | Runtime panic on overflow (signed), silent wrap (unsigned) | Panic in debug, wrap in release | Explicit @addWithOverflow builtin | First-class checked arithmetic with overflow detection |
| Profile gating | N/A | N/A | N/A | :core / :service / :sovereign capability ladder |
| Sigil clarity | N/A | #[attribute] / macro!() / const fn (three syntaxes) | @builtin (47+ builtins behind same sigil) | $meta sigil; visually distinct, deliberately small set |
Where Each Competitor Breaks
Section titled “Where Each Competitor Breaks”Go — Simplicity as Surrender
Section titled “Go — Simplicity as Surrender”Go doesn’t have metaprogramming. Full stop. go generate is “please run this Python script before you compile.” The language designers philosophically rejected compile-time evaluation. If you need generic code, you copy-paste or use interface{} and pray. Go 1.18 generics helped, but there is still zero comptime. You cannot compute a lookup table at compile time. You cannot unroll a loop. You cannot introspect a type’s fields without reflect at runtime.
Go chose simplicity over power. Janus chose structured power over false simplicity.
Rust — Three Half-Systems
Section titled “Rust — Three Half-Systems”Rust has the most capable metaprogramming of the three — but it is fractured into three incompatible subsystems:
const fnevaluates pure functions at compile time but can’t do anything interesting. No trait method calls, limited control flow until recently.- Proc macros are powerful but operate on token streams. They don’t see types, they don’t see the semantic graph, they compile as separate crates with separate build steps.
#[derive]is a third mechanism with its own rules.
The result: you need syn, quote, proc-macro2 as dependencies just to write a derive macro. The compile-time ecosystem is a dependency swamp.
Janus gives you one airlock to the compiler’s semantic graph. You see types, effects, capabilities. Not token soup.
Zig — Beautiful Concept, Structural Problems
Section titled “Zig — Beautiful Concept, Structural Problems”Zig is the closest competitor and the one we respect. Zig’s comptime is elegant in concept: the same language runs at both compile time and runtime. But it has structural problems:
47+ @builtins behind one sigil. @intCast, @ptrCast, @typeInfo, @This, @ctz, @popCount. The sigil carries no semantic weight; it just means “here be compiler magic.” Janus splits this into stdlib generics, $meta builtins for compiler introspection, and regular library calls for everything else. Most of Zig’s @builtins become ordinary function calls in Janus.
No resource limits. A Zig comptime block can allocate unbounded memory and loop forever. The compiler just hangs. Janus’s ComptimeEvaluator has explicit budgets. When you exceed them, you get a diagnostic — not a frozen terminal.
No capability gating. In Zig, comptime has full access to everything. In Janus, :core comptime can compute sizes and unroll loops. It cannot allocate or introspect. That requires :service or :sovereign. The profile ladder prevents accidental complexity escalation.
The Doctrinal Win
Section titled “The Doctrinal Win”Zig gives you all of comptime and trusts you. Rust gives you three half-systems and hopes you pick the right one. Go gives you nothing and calls it a feature.
Janus gives you a graduated airlock with explicit resource limits, visual sigil distinction, and profile-gated capability escalation.
You can do metaprogramming now. But more importantly: you can do governed metaprogramming. And that is the thing none of them have.
See also: Comptime Reference — full builtin table, profile matrix, and code examples.