Koru Renames the event Keyword to tor
event was the wrong word, and it had been the wrong word from the beginning.
It arrives carrying baggage from event-driven programming: a listener, a callback, something reactive that happens to your program while it waits. Nothing in the construct carries any of that. What it actually declares is the agentive surface of a named operation — who performs it, what gets done to, and the named ways control can leave.
So the keyword is now tor.
import std/io
tor greet { name: string } -> string
greet -> "Hello, " ++ name ++ "!"
greet (name: "World"): msg |> std/io:print.ln(msg) The doer
The Proto-Indo-European agentive suffix *-tor / *-ter forms agent nouns:
the one who does X. It survives into Latin as -tor and into Sanskrit as -tṛ, and it is the most familiar word-formation you never think about:
actor, creator, monitor, mentor, operator, dictator.
Every one is “the one who does the thing.” We are not coining a word here — we are wearing flat a formation that English speakers already parse unconsciously.
The Sanskrit branch makes it sharper. kartṛ — from the root √kṛ, “to do or
make” — is the grammatical name for the agent role: the one who performs the
action. A tor declaration is exactly that role, lifted into the type system.
It names the doer and states what doing looks like from the outside.
And here is the part that makes the keyword work rather than decorate. The suffix has not been renamed into a keyword — it has been moved to the front:
tor greet { name: string } -> string tor greet is a greeter. tor check is a checker, tor classify is a
classifier, tor render is a renderer. You never write the agent noun; you write
the agentive morpheme in front of the verb and your own language finishes the
word.
Koru’s test suite has been doing this since long before the keyword existed. The
most common declaration names in the corpus are open, close, process, compute, connect, accumulate, create — and several of those are already standard -or agent nouns in English: a processor, a computer, a connector, an accumulator, a creator. The convention falls out
without needing to be taught: name a tor with a verb, and the reader gets the
doer for free.
The done-to
Here is where the etymology stops being decoration and starts doing work.
That same root √kṛ gives Sanskrit its other case role: karman — the patient, the thing acted upon. Classical Indian grammar separates the two cleanly. The doer is kartṛ. The done-to is karman.
Look again at the input fields:
tor greet { name: string } -> string The braces are not an arbitrary parameter list borrowed from C. Under the karman reading they are the patient case: what gets done-to, declared right beside the doer that does it. Agent and patient, separated at the surface of the language the way Proto-Indo-European grammar separated them a few thousand years ago.
That is not a metaphor we projected onto the syntax. It is a description of what the syntax was already doing.
The gate
German gives the same five letters a second, independent meaning: das Tor is a gate. The Brandenburger Tor is the Brandenburg Gate. (Not to be confused with der Tor, “the fool” — different gender, different word entirely.)
And the gate reading lands on the same mechanic from a completely different
angle. A caller arrives at a tor carrying inputs, and leaves through one of its named exits:
tor check { n: i64 }
| big i64
| small i64
check = if(n > 10)
| then => big n
| else => small n
tor classify { n: i64 } -> i64
classify = check(n)
| big b -> b * 100
| small s -> s | big and | small are the gate’s ways out. The caller does not receive a
value and then decide what to do — it threads through the exit the doer chose.
This is the half of the construct that no other language lifts into the
signature: the continuation branches are part of the declared type, so what
happens next is typed by the callee, not improvised by the caller.
Three independent roots — the PIE doer, the German gate, the Norse thunder god for anyone who wants him — converging on five letters, each naming a real part of the same mechanic. We picked the word for the first one. The second arrived for free.
Isn’t this just a function?
Almost, and the difference is the whole point. A function hands back a value and
the caller decides what happens next — that decision lives in the caller’s head,
and nothing checks it. A tor declares the ways out. | big and | small are
part of its type, so the caller does not receive a result and branch on it; it
threads through the exit the doer selected.
The practical consequence is that you cannot forget an outcome, and you cannot invent one that was never declared. Control flow stops being something you write by hand at every call site and becomes something the type system carries — which is the thesis the rest of the language is built on. There is more to say about obligations, effects, and what a tor can promise about resources; that is for the docs, not a naming post.
What actually changed
Nothing about the semantics. Not one rule about branches, obligations, phantom state, or how control threads through a call. The construct is exactly what it was yesterday.
It just stopped being called the wrong thing.
A tor is the doer — kartṛ, the one who acts. Its input fields are the karman,
the done-to. Its branches are the gate’s named exits. And proc, from Latin procedere, “to go forward,” is the going-forward that actually does the work.
Noun and verb, at the spine of the language.