On 25/04/2013 5:29 PM, Brian Anderson wrote:
It's almost taboo here, but we could consider adding catchable exceptions.
For reference sake on this taboo -- let it not be too opaque! -- I will
point to the amazing powers of IRC logging, and the conversation that
contains the memorable phrase:
<graydon> please remind me of these things next time someone asks
us about "resumable exceptions"; I had forgotten how
convinced I was of this last time through the design-space
http://irclog.gr/#show/irc.mozilla.org/rust/381023
In particular, to summarize for the impatient: once you get resumable
exceptions, your code can only be correct if it leaves every data
structure that might persist through an unwind-and-catch (that it
acquired through &mut or @mut or the like, and live in an outer frame)
in an internally-consistent state, at every possible exception-point.
I.e. you have to write in transactional/atomic-writes style in order to
be correct. This is both performance-punitive and very hard to get
right. Most C++ code simply isn't correct in this sense. Convince
yourself via a quick read through the GotWs strcat linked to:
http://www.gotw.ca/gotw/059.htm
http://www.gotw.ca/gotw/008.htm
Now granted, we don't have 'operator=' overloading, so some quantity of
this is exaggerated. But not much. Any nontrivial sequence of writes and
other-operations winds up requiring transactional treatment if you have
resumable exceptions. This is a big tax.
If we stay away from that feature, we get to hold on to sequential
logic. Your can reason about state strictly in terms of "the sequence of
operations as-written", or prefixes thereof. You never have to think
about "someone might call another method on this object after it was
half-modified and unwound mid-operation".
I was only thinking that instead of
condition! { io_error: super::IoError -> (); }
you might have
condition! { file_not_found_error: super::FileNotFoundError -> Foo; }
condition! { file_permission_error: super::FilePermissionError -> Bar; }
and so forth. In other words, instead of the branching in the IoError
enum, branching at the condition and error-describing-type level. That
only makes sense in the as-you-would-expect-a-condition-system-to-work
scenario though.
This is attractive, but how could you then create a block of code that
trapped *all* errors?
I would be _totally_ amenable to enhancing the condition-declaring
system to provide a means of chaining the default of a condition into
raising a different one at the declaration-site. We have to do some
further hacking on the condition-declaring system anyways, to handle
passing & properly.
At the moment, you _could_ do this if you were fastidious about it at
the raise sites. Namely:
condition! { file_not_found_error: (Path) -> File; }
condition! { general_file_error: (Path, File) -> File; }
condition! { general_io_error: ~RtStream -> ~RtStream; }
...
let p = Path::new(...);
...
do file_no_found_error.cond.raise_default(copy p) {
let f = File::null_file();
do general_file_error.cond.raise_default(p, f) {
File::stream_file(general_io_error.cond.raise(f.rts));
}
}
If you moved this kind of idiom into a helper function, you could call
it from multiple locations without much boilerplate or possibility of
getting the chaining wrong. But it'd be nicer to do it at
condition-declaration site, certainly. More arguments for revisiting the
condition! macro.
Unfortunately there is no equivalent to `Typeable` yet in Rust, but we
have talked about it (called `Any`). I would also like `fail!()` take an
`Any`, so this seems like an appropriate place for it.
+1 yes please. I suspect we're _close_ to having enough machinery for
this now.
-Graydon
_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev