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 Initializers as throws¶
Initializers can be declared with the throws
keyword. This enables uncaught
errors in the initializer body to be propagated outside of the initializer (see
Calling Throwing Functions). When an error is thrown, the memory that
would have been used for the result of the initializer call will be cleaned up
before the error is thrown back to the caller.
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;
this.complete();
validate(this);
}
}
Calling Throwing Functions¶
When an initializer is declared with the throws
keyword, calls to throwing
functions may be made in the body of the initializer after this.complete()
(see Limitations on Instance Usage in Initializers for information on
this.complete()
and the example in Declaring Initializers as throws).
As a result, thrown errors will be propagated outside of the initializer. The
memory that would have been used to store the instance created by the
initializer will be cleaned up prior to propagating the error.
Note
Calls to throwing functions are not currently allowed prior to
this.complete()
.
When an initializer is not declared with the throws
keyword, calls to
throwing functions may be made anywhere in the body of the initializer. Such
calls will cause the program to halt (see Error Handling) if
errors are encountered.
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 tothis.complete()
(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; this.complete(); 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; this.complete(); } }