Statements
Exceptions: throw, try and catch
Throwing a value that implements IException, catching it by type, and the standard exception hierarchy.
since 0.1.0-alpha.1linuxwindowswasm
Description
throw expr; transfers control out of the current function, like return. The thrown value must implement IException; throwing anything else, such as throw 5;, is a compile error.
try stmt catch (Type name) stmt runs the first statement and, if it throws, hands the exception to the first catch clause whose declared type the thrown value is assignable to. Selection uses the thrown value's actual class and goes through its base classes and the interfaces it implements, so a clause for a base class or for an interface catches every subclass. The clauses are tried in order and only the first match runs. The binding name is optional: catch (Exception) { ... } catches without naming the value.
An exception that no clause catches ends the program with Uncaught <Class>: <message> and exit status 1.
There is no finally. For cleanup that must run however the code is left, use a using declaration (lang.using-statement); ordinary try and catch cover the rest.
The standard exceptions live in namespace std, which is imported implicitly. Interfaces define what can be caught, and the classes carry the message:
| type | kind | extends or implements |
|---|---|---|
IException |
interface | requires a string message and string toString() |
Exception |
class | IException |
IRuntimeException |
interface | IException |
RuntimeException |
class | Exception, IRuntimeException |
ILogicException |
interface | IException |
LogicException |
class | Exception, ILogicException |
To define your own exception, extend Exception and call its constructor with the message.
Choosing a catch clause by type
class ValidationError : Exception {
int field;
new ValidationError(string msg, int f) {
Exception::Exception(msg);
field = f;
}
}
void check(int n) {
if (n < 0) throw ValidationError("negative", n);
if (n == 0) throw LogicException("zero");
if (n > 100) throw RuntimeException("too big");
console.writeln("ok ${n}");
}
void attempt(int n) {
try {
check(n);
} catch (ValidationError e) {
console.writeln("validation: ${e.message} field=${e.field}");
} catch (RuntimeException e) {
console.writeln("runtime: ${e.message}");
} catch (IException e) {
console.writeln("other: ${e.message}");
}
}
attempt(5);
attempt(-3);
attempt(0);
attempt(500);
ok 5
validation: negative field=-3
other: zero
runtime: too big
Rules
- The thrown value must implement
IException. - A
catchclause matches when the thrown value's class is the clause's type, a subclass of it, or implements it as an interface. The first matching clause runs; the rest are skipped. - Put the more specific clauses first. A clause for
IExceptionplaced first would catch everything and leave the later ones unreachable. - The name in a
catchis optional. - A
catchblock may throw again, from the same or a different exception type, and an enclosingtrycan catch it. - An uncaught exception terminates the program with
Uncaught <Class>: <message>and exit status1. - A
tryhas nofinally.
Examples
Catching without a name, and rethrowing a different exception
try {
throw Exception("plain");
} catch (RuntimeException e) {
console.writeln("never reached");
} catch (Exception) {
console.writeln("caught without a name");
}
try {
try {
throw LogicException("inner");
} catch (LogicException e) {
console.writeln("rethrowing ${e.message}");
throw RuntimeException("outer from ${e.message}");
}
} catch (RuntimeException e) {
console.writeln(e.message);
}
caught without a name
rethrowing inner
outer from inner
throw 5;
// error: thrown value must implement IException (got 'int')
try {
console.writeln("a");
} finally {
console.writeln("b");
}
// error: expected 'catch' clause
Notes
The runtime failures that the language raises itself, such as an out-of-range index or division by zero, are RuntimeExceptions, so catch (RuntimeException e) handles them.
See also
- IException — The interface that every thrown value must implement.
- Exception — The base class of the standard exceptions, holding a message.
- RuntimeException — The error the standard library throws when an operation fails at run time.
- LogicException — An error that signals a mistake in the program's own logic, such as using an object in the wrong state.