Skip to content

Error

Error is the protocol a value must conform to before it can be thrown with throw.

class IOError <Error> { ... }

An error is an ordinary heap object, not a special kind of value. It follows ARC like any other object, and a caught error is a strong local released at the end of its catch scope. Errors reuse the protocols, RTTI and object model already in the language rather than adding a separate mechanism.

Conforming requires a single method, so a handler can always describe what it caught without knowing the concrete type.

String* message(void);

Return a human-readable String describing the error. It is the only requirement, so every handler can report a caught error generically:

try { i32 n = readCount(p); }
catch (e) { Stdio.printf("failed: %s\n", e.message().cString()); }

Error is a contract for user-defined error types; the standard library ships no conformers. A typical conformer stores its own detail and returns it:

class IOError <Error> {
String* msg;
void init(String* m) { msg = m; }
String* message(void) { return msg; }
}
i32 readCount(String* path) throws {
File* f = File.open(path);
if (!f) throw new IOError(String.withCString("cannot open"));
defer { f.close(); } // runs on the throw path too
return f.readInt();
}

Make any class you intend to throw conform to Error. A bare catch (e) binds the caught value and can call message generically. Typed handlers such as catch (IOError e) resolve through the same RTTI downcast that works across module boundaries, so the protocol needs nothing extra for them.

See also Object and the sibling protocols Comparable, Hashable, Copying and Enumerable.