This is a suggestion for adding an exception system to Rust that satisfies
these requirements:
1. Unwinding does NOT pass through code that is not either in a function that
declares throwing exceptions or in a try block (instead, that triggers task
failure)
2. Callers can ignore the fact that a function throws an exception, resulting
in task failure
3. Callers can handle exceptions if desired, with the same syntax of C++, Java
and C#
(1) avoids the issue with C++ exception handling forcing to think about
exception safety everywhere
(2) avoids the issue with Java's checked exceptions forcing to explicitly
handle or redeclare them
(3) provides an easy-to-use exception mechanism
The specification is based on adding some syntax sugar, which is then
transformed by the compiler into the current Rust syntax, and thus does not
really alter runtime behavior (but it is also possible to implement this with
traditional unwinding if desired).
Functions can be declared to throw exceptions, and if the conceptual unwinding
process would have to pass through a function call that does not declare
throwing an exception of that type, task failure is invoked instead.
To integrate with the condition system, one can raise a condition instead of
throwing, and declare the condition type and handlers with "throws", allowing
them to throw exceptions if desired (note that of course this will just result
in task failure unless the function raising the condition is declared to throw).
It is of course possible to code using this style "by hand", but the syntax
sugar allows to do it in a much terser way, and allows to convert functions
that use task failure to functions that throw exceptions without changing the
source code of callers that don't want to handle them.
* New syntax added:
- "throws E1, E2, ..." modifier on functions and closures
- try/catch block
- try() expression
- throw e statement
* New type declarations added:
enum Result1<T, E1>
{
Ok(T),
Fail(E1)
}
enum Result2<T, E1, E2>
{
Ok(T),
Fail1(E1),
Fail2(E2)
}
... and so on...
* Transformations to implement the system:
Everywhere:
fn foo() -> T throws E1 [similar with closures] => fn foo() -> Result1<T, E1>
fn foo() -> T throws E1, E2 [similar with closures] => fn foo() -> Result2<T,
E1, E2>
try(f(args)) [if f declared with throws] => f(args)
f(args) [if f returns T and is declared with throws, not inside try()] =>
match f(args) {Ok(x) => x, Fail1(e) => throw e, Fail2(e) => throw e, ...}
In functions declared throws:
return v => return Ok(v)
try {try_body} catch(e1: E1) {catch_body} catch(e2: E2) {catch_body}
=>
let mut e1_: Option<E1> = None;
let mut e2_: Option<E2> = None;
'try_: loop {try_body; break;}
if e1_.is_some() { let e1 = e1_.unwrap(); catch1_body }
else if e2_.is_some() { let e2 = e2_.unwrap(); catch2_body }
throw e, if there is any containing try block that has a catch block with
argument eK with type EK such that e is convertible to EK (taking the innermost
suitable try block and the first suitable catch block)
=> eK_ = Some(e); break 'try_
throw e, if there are no suitable try blocks but the function is declared
throws and e is convertible to throws type EK
=> return FailK(e)
throw e, otherwise, if e implements ToStr:
=> fail!(e.to_str())
throw e, otherwise:
=> fail!()
_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev