Throwing Initializers¶
Overview¶
Initializers (see Class Initializers) and Error Handling are currently in the process of being integrated together. Support for the overlap of these features is currently limited, but key functionality has been enabled.
Using Catch-less try!¶
try!
can be used anywhere in the body of any initializer, so long as it does
not have an associated catch
clause. When used, any error encountered will
cause the program to halt.
Example (try-bang-init.chpl).
proc throwingFunc(x: int) throws {
if (x > 10) {
throw new Error("x too large");
} else {
return x;
}
}
record Foo {
var x: int;
proc init(xVal: int) {
x = try! throwingFunc(xVal); // try! here is legal
/* The following code is not legal in an initializer yet, due to
having a catch clause:
try! {
x = throwingFunc(xVal);
} catch e: Error {
x = 9;
}
*/
}
}
Declaring throwing Initializers¶
Like typical routines, initializers and post-initializers
(postinit()
procedures) can be declared with the throws
keyword. This enables errors encountered during object initialization
to be thrown back to the calling context. When an error is thrown
during either of these calls, the compiler ensures that the
deinit()
routine for each initialized field is called, and that
the memory allocated to store the object is freed.
Note that, at present, this feature has the following limitations:
Initializers can only throw errors after the
init this
statement (see Limitations on Instance Usage in Initializers for more information aboutinit this
). One implication of this is that the initializer of a superclass may notthrow
since its invocation precedes theinit this;
statement.Initializers can only throw errors by making calls to throwing routines, not by directly executing
throws
statements.
The following is an example of a throwing initializer that relies on a
throwing helper procedure, validate()
, called after its init
this; statement:
Example (init-declared-throws.chpl).
proc validate(r: R) throws {
if (r.x > 10) {
throw new Error("x too large");
}
}
record R {
var x: int;
proc init(xVal: int) throws {
x = xVal;
init this;
validate(this);
}
}
As in typical procedures, if an initializer is not declared with the
throws
keyword, yet makes a call that throws an error, the program
will halt if errors are encountered (see
Error Handling).
Future Work¶
We intend to fully support throwing initializers in the future. This will include:
being able to
throw
from anywhere in the body of an initializerbeing able to write
try
/try!
withcatch
blocks anywhere in the body of an initializerbeing able to call functions that
throw
prior toinit this
(see Limitations on Instance Usage in Initializers for a description) - includingsuper.init
calls when the parent initializer throws, e.g.,class A { var x: int; proc init(xVal: int) throws { x = xVal; init this; someThrowingFunc(this); } } class B : A { var y: bool; proc init(xVal: int, yVal: bool) throws { super.init(xVal); // This call is not valid today y = yVal; init this; } }