Skip to content

v2026.7.3: Representation & Layout Doctrine (SPEC-246)

v2026.7.3: Representation & Layout Doctrine (SPEC-246)

Section titled “v2026.7.3: Representation & Layout Doctrine (SPEC-246)”

Janus now has a constitutional answer to a question most languages leave implicit: what does a struct mean in memory, and who decides?

The answer is layered, explicit, and proven by the compiler — not folded into a keyword.

A struct defines what fields exist. @layout(...) defines how they’re stored. @repr(...) defines how each field is encoded. Those are three different questions, and Janus keeps them apart.

See Representation & Layout for the full reference; this note covers what changed and why.

A struct’s physical organization is now selected by an attribute, not a keyword:

ProfileUse
stable (default)deterministic, correctness-preserving — most structs
optimalopt-in compiler optimization (Rust-style reordering)
wirearchitecture-independent binary contract (SSTable, SKV, SBI, protocols)
packedexact density, no padding
cC ABI (FFI)
simd / cachelinehardware alignment
opaqueintentionally unknowable (handles, runtime internals)

A struct with no @layout(...) is @layout(stable). That default is chosen on failure-mode asymmetry grounds: forgetting an optimization shows up in a profiler, forgetting a binary contract shows up in production.

A struct declared @layout(wire) may be proven WireSafe — the compiler certifies it has a fixed layout, no process-local ownership, no pointers, and exactly one canonical byte representation per value. There is no unsafe impl WireSafe. If the compiler can prove it, it does; if it can’t, you get a precise diagnostic and the answer is “express the design differently” (use a codec, not a type lie).

The Canonical Representation Principle unlocks a remarkable consequence: for T: WireSafe, equality, hashing, serialization, disk-mapping, and fingerprinting all derive from one canonical byte sequence. a == b may lower to memcmp. hash(a) is BLAKE3 of canonical bytes. socket.write(&value) needs no serializer.

The historical extern struct Foo { ... } is now parser sugar that the compiler rewrites during parsing to:

@layout(c)
@repr(native)
struct Foo { ... }

After parsing, the frontend never sees extern struct — there is exactly one semantic representation of layout in the AST. Compiling extern struct emits:

W1204: `extern struct` is deprecated.
Use:
@layout(c)
struct Foo
`extern struct` is a parser alias for `@layout(c) @repr(native)` and
will be removed in Janus 2.0.

Existing source keeps compiling. Migrate when convenient. The deprecation follows a general policy we’re naming for the first time:

Syntax Evolution Doctrine — language evolution preserves semantics before syntax. Old syntax parses; the compiler lowers to the new semantic form; warnings educate; a later edition removes the obsolete syntax.

Because keeping it as a parallel grammar path reintroduces exactly the problem SPEC-246 solves. Today @layout(...) is the one place layout lives. If extern struct survived, eventually someone would want extern packed struct, extern simd struct, extern cacheline struct — a new keyword every time a new representation policy appears. The attribute system absorbs all of them without touching the grammar.

Why stable as the default (not optimal / Rust-style)

Section titled “Why stable as the default (not optimal / Rust-style)”

Two arguments, in priority order:

  1. Failure-mode asymmetry. A forgotten optimization is observable in a profiler. A forgotten correctness boundary (wire format, ABI) is observable six months later in production. A language for capability-safe kernels and protocols should default to the correctness-preserving failure mode.
  2. Domain fit. Janus’s target domain — databases, protocols, zero-copy, sovereign kernels — spends more time at the systems boundary than Rust’s. Stable layout is the more valuable default there. (But argument 1 is load-bearing; argument 2 is supporting.)

This SPEC elevates four principles to sit alongside ownership, effects, capabilities, and profiles:

The Implicit-Contract Principle — implicit facts are acceptable if mechanically derivable from explicit declarations; implicit contracts are not. (Justifies auto-derived WireSafe; rejects hidden ABI.)

The Representation-Orthogonality Principle — “what fields exist?” and “how are they stored?” must not be conflated.

The Canonical Representation Principle — a value in a declared binary contract has exactly one valid in-memory representation. Padding, inactive-union payloads, and NaN payloads are not distinct valid representations.

The Representation-is-a-Type-Property Principle — representation is a property of the type, not a property of serialization. Serialization, hashing, equality, and fingerprinting derive from the type’s representation; they do not define it. This is what distinguishes Janus from Rust, Zig, C, Swift, Go, and most serialization frameworks.

  • Layer 1 (compiler): parser rewrite of extern struct, @layout(...) attribute parsing, WireSafe derivation pass, the new diagnostics (E2301E2306, E2412E2413, W1204).
  • Layer 4 (monastery): teaching material on layout profiles and WireSafe; mission updates for any mission using extern struct.
  • Future (v0.2): wire-layout-change fingerprinting diagnostic; composable @layout { ... }; configurable canonical NaN.
BeforeAfter
extern struct Foo@layout(c) struct Foo
extern struct Foo (BE protocol)@layout(c) @repr(network) struct Foo
wire-format extern struct Foo@layout(wire) @repr(network) struct Foo (and prove WireSafe)

The third row is a semantic upgrade, not a mechanical edit: moving a type to @layout(wire) commits it to a binary contract and triggers the WireSafe proof. Use it for types that genuinely cross persistence or network boundaries.


Developed with Voxis Forge assistance over a four-turn design conversation; ratified as Position A+ (Canonical Representation) per Founder decision 2026-07-03. Operational spec: .agents/specs/_PROPOSED/SPEC-246-representation-and-layout-doctrine.md.