Error Handling¶
This README describes the early version of error handling implemented in Chapel 1.15. For a complete explanation of the final design and rationale, refer to CHIP 8.
Errors¶
A base class Error
is defined in the Chapel standard modules.
It includes an initializer accepting a string argument, which is the error
message to display if the error is not caught.
Users may use the provided Error
directly, or create their own error
hierarchy with Error
at its root.
class MyError: Error {}
class MyIntError: MyError {
var i: int;
}
While defining a standard set of Error
subclasses is planned for the
future, Chapel only provides Error
at present.
Throwing Errors¶
throw
statements throw errors from a function to its callee.
// throwing a newly created error
throw new Error("error message here");
// throwing an error stored in a variable
var e: Error;
// ... set e ...
throw e;
If a function may throw an error, it must be declared with throws
.
proc mayThrowErrors() throws { ... }
proc mayThrowErrorsAlso(): A throws where ... { ... }
proc mayNotThrowErrors() { ... }
Handling Errors¶
Chapel supports two modes for error handling: strict mode for production code, and default mode for drafting and iterating. Strict mode forces users to explicitly mark throwing calls and handle errors, clarifying the program's control flow to the user and the reader. Default mode loosens those requirements with implicit error handling.
Strict mode is enabled by passing --strict-errors
to the Chapel compiler,
otherwise the compiler will use default mode.
Strict Mode¶
try
/try!
blocks and their associated catch
clauses allow the user
to create a handler for a throwing call.
- Statements that contain throwing calls must be enclosed in a
try
block.- If an error is raised by a call in a
try
block, the rest of the block is abandoned and control flow is passed to the list ofcatch
clauses.
- If an error is raised by a call in a
- Each
catch
clause may contain a type filter. If the error's type matches the type filter, the block associated with thatcatch
clause (and only that block) will be executed.- These filters will be evaluated in order of declaration, so even if a more exact filter is present in the list, it will not be selected if a matching general filter precedes it.
- If no filter is included, or only an error variable name is provided, then all errors will match. A clause with such a filter must be declared at the end of the list, since clauses that follow it could never be executed.
- Unless the
catch
clause block contains athrow
, execution will resume after thetry
block.
try {
mayThrowErrors();
mayThrowErrorsAlso();
} catch e: MyIntError {
writeln("caught MyIntError " + e.i + ", continue");
} catch e: MyError {
throw e;
} catch {
writeln("unexpected error");
}
- If none of the type filters matches the error, a catchall block will be
inserted. Its functionality will depend on whether a
try
ortry!
was used.- If
try
was used, the error will be propagated. (More on this below.) - If
try!
was used, the program willhalt()
.
- If
try
blocks may be used without anycatch
clauses, or without brackets for single statements.
try {
ioSourceOne();
ioSourceTwo();
ioSourceThree();
}
try! cannotFail();
try! var x = requiredVariable();
Propagation¶
Propagation means that the error will be passed off to a set of handlers beyond the current scope. This can be accomplished in two ways:
- Out of the enclosing function, if the function is declared with
throws
.
proc ioSetup() throws {
try {
ioSourceOne();
ioSourceTwo();
ioSourceThree();
}
}
- To the catch blocks of an enclosing
try
.
try {
writeln("outer try");
try {
writeln("inner try");
throw new MyError();
} catch err: MyIntError {
writeln("MyError should not be caught here");
}
} catch err: MyError {
writeln("caught MyError");
}
Default Mode¶
In addition to the features in the Strict Mode section, default mode allows
throwing calls to be called without being enclosed by a try
or try!
block. This is done by inserting an implicit handler after the call:
- If the caller is declared with
throws
, any error encountered will be thrown in turn. - If the caller is not declared with
throws
, the program willhalt()
if any error is encountered.
Current Limitations¶
- In general it is not possible to use error handling with parallel or
multilocale constructs.
forall
,begin
,on
, etc.- However it is possible to use throwing calls handled entirely within the scope of a given construct, without propagation.
- Errors may not be generic classes.
- Virtual methods cannot throw. In practice, this means that while a typical class may contain throwing methods, a class that is extended or a class that is extending another class may not contain throwing methods.