Throwing and catching
throw raises an instance of an archetype; catch takes it by its exact type.
An error, in Archon, is an instance of an archetype — section 7 just gave you everything needed to understand one.
archetype FailedPotion {
message: str;
}
archetype Still {
distil(dose: int) -> int {
if (dose > 3) {
throw FailedPotion(message: "too much mandrake");
}
return dose * 2;
}
}
@entry(start)
object MyProgram {
start() {
var still := Still();
try {
Console.print(text: $"essence: {still.distil(dose: 2)}");
Console.print(text: $"essence: {still.distil(dose: 5)}");
Console.print(text: "never reached");
} catch (raised: FailedPotion) {
Console.print(text: $"failed: {raised.message}");
}
Console.print(text: "the program goes on");
}
}
throw raises an instance
throw FailedPotion(message: "too much mandrake");
FailedPotion is an ordinary archetype — a message field, nothing special, not even an
imposed naming convention. throw raises an instance of it, built like any other. Never a
bare value: an error carries what it takes to tell its story, and an archetype is what knows
how to carry fields.
And remember 5.2: throw ends the method as well as return does. A method that throws
returns nothing — it has answered another way.
The error climbs until a catch
distil(dose: 5) throws deep inside the still; the catch is in start. In between, the
error climbs: it leaves distil, skips the “never reached” line, and looks for the first
catch that matches. Uncaught, it would have climbed to the entry point and stopped the
program — which is what 6.1 showed you.
} catch (raised: FailedPotion) {
Console.print(text: $"failed: {raised.message}");
}
The catch names a type and receives the raised instance: raised.message reads its field,
like any field from section 7.
The match is exact
catch (raised: FailedPotion) only takes what was thrown as FailedPotion — never
another archetype that happens to have the same fields. It is a deliberate departure from the
rest of the language: here the type’s identity matters, not its shape.
Your turn
- Set the first dose to 4: the “essence” line disappears, the failure comes on the first call.
- Remove the
try/catchand keep the dose at 5: the error climbs to the very top, the program stops — “the program goes on” never prints. - Give
FailedPotiona second field —dose: int— throw it filled, and print it in thecatch. An error carries whatever you put in it.