Abstract Tors: The Boundary That Holds by Construction
Every architecture doctrine has one rule that matters. Clean Architecture’s is the Dependency Rule: depend inward, keep your boundaries, never cross a layer. It is the whole point of the exercise. And in every language that teaches it, the rule is held by attention — by code review, by discipline, by the hope that tomorrow’s commit believes in it as much as today’s.
A boundary held by attention is a boundary that decays.
The seam is the thing to make first-class
The reason the doctrine needs so much scaffolding is that its central abstraction — an interface you can swap the implementation behind — has no home in the type system. The language cannot see the relationship between IUserRepository and UserRepository. Nobody can verify it and nobody is responsible for it. So replacement demands a whole apparatus: the interface, the concrete class, the DI container, the registration, the constructor injection. That barrage is not the design. It is the tax you pay because the mapping between an abstraction and its implementation is an unverifiable convention.
Koru makes that one fact first-class. An abstract tor is a contract — a signature and its outcomes — that the compiler can see, resolve, and enforce.
// The contract: given a context, produce an integer. Nothing else.
[abstract] tor coordinate { ctx: i32 } -> i32
// The library's sensible default — what you get before you wire a real one.
proc coordinate|zig {
std.debug.print("Default coordination: {}\n", .{ctx});
return ctx;
}
// The app's real implementation — allowed to delegate to the default.
input:coordinate =
coordinate(ctx: 42) // Delegates to default
| finished f -> f + 1 That is the whole seam. A contract, a default, an override. No interface, no container, no registration — just three declarations the compiler understands and checks.
The wall stands because the compiler stands behind it
Everything that makes the Dependency Rule weak in mainstream languages becomes a checked fact here:
- The mapping is real syntax, not a convention. An abstract tor has exactly one implementation claim — a second is refused. There is no
MyRepository : IRepositorypair to keep in sync; there is one contract and the pairing is verified. - Forgetting to wire the seam is a build error, not a runtime outage. A port that nothing implements does not compile, and the compiler names the port in prose. The failure mode of “we forgot the boundary” is a red build, not a 3 a.m. page.
- The seam is free. Resolution happens at compile time; the indirection you’d normally budget for — vtables, a container, extra objects — erases to nothing in the binary.
- The caller is the one thing that never changes. Replace the implementation behind the port and the call site is byte-identical — which is the entire promise of dependency inversion, delivered without the apparatus.
Interfaces are a symptom
The point is not that Koru has fewer words for the same thing. It is that the need for the words is gone. An interface exists to permit replacement behind a boundary a caller depends on — and it is load-bearing exactly because the mapping it guards is unverifiable. Remove that verification gap and the interface’s reason to exist goes with it.
That is why the barrage of interfaces is a symptom, not a design. The disease is an abstraction-to-implementation mapping the compiler cannot see, which forces you to build the mapping by hand and then to spend further effort proving you didn’t get it wrong. Koru doesn’t add a better way to write interfaces. It makes the mapping a fact, and the scaffolding evaporates.
This is the same argument this site made about granularity — that small, focused events should be rewarded instead of taxed. The abstract tor is the seam half of that story: the architecture wall you are supposed to maintain by hand is maintained by the compiler, and it costs nothing to keep.
What this is not claiming
Saying the compiler now enforces the boundary is not saying the discipline is fully won. No type system stops a team from churning code for its own sake — the cultural rot Clean Code criticizes is a people-problem, and proof obligations do not fix people. What the language does is make the one technical law worth keeping — the boundary holds — hold by construction. The part that was a convention becomes a checked fact; the part that was a culture stays a culture, and it is not this language’s job to police it.
And the scope is honest: this is build-time replacement — you wire which implementation is live when you compile, which is how dependency injection is actually used the majority of the time. A genuinely runtime-selected strategy is a different mechanism and a different post.
The shape of the thing
Clean Architecture promised that boundaries built properly would save you. What it could not promise was that the boundaries would stay built. Koru’s abstract tor is the answer to the one part worth keeping and the part that always rotted: the wall that holds. Not because anyone remembered to hold it — because the compiler did.