On 19/11/2011 2:31 PM, David Rajchenbach-Teller wrote:
Let's switch vocabulary, then. "Report" and "Handle" are probably less
loaded with implicit meanings.
Sure. Those are good terms. So long as it's clear there are a few
dimensions to the issue:
- What is checked statically (if at all) for exhaustiveness.
- Whether you can recover at the reporting site or must always
unwind a bit (say, to the nearest handler).
- Whether you permit unwinding at all.
- Whether unwinding, once started, is permitted to stop before it
unwinds the whole task.
- If you can stop (catch) an unwinding early, what the meaning of
that is in terms of the consistency or inconsistency of the local
heap.
- How handlers are located and associated (globally, by dynamic scope,
by type, by static region, by task ownership, etc.)
Can I assume that your example is actually too short to demonstrate the
meaningful difference with C++/ML-style exceptions and that the
following would also work?
I think the example I gave was long enough, but I guess it depends how
you look at it. The salient point is that recovery happens w/o
unwinding. The dynamic scope is *searched* to find a handler, but the
handler is invoked w/o any unwinding, and since the handler succeeds
(executes a 'ret', returning a value to the reporting site) execution
continues at the reporting site. No unwinding occurs.
Unwinding is limited to failure only, which is also unrecoverable (so
there's no question of "what happens to the local heap on unwinding" --
it's always thrown away)
If I understand correctly, Rust 0.x will offer:
* tasks that are lightweight enough that we can theoretically afford to
launch as often as we want just for error-handling;
I'd like that to be true. It's hard to promise.
* tasks that are first-class.
I'm not sure what this means in the context of this discussion.
In addition, I am nearly certain that we wish to be able to display a
different error message to handle, say, a failure of a module due to a
network error or a failure of the same module doing exact the same thing
but due to a disk error. Therefore, I also understand that:
* `fail` or some variant thereof can actually report a failure reason,
(presumably as task-bound value with type `any`)
We have no 'any' type yet. When we do, I'd like this to be true.
If so, in effect, we already have Report-and-handle, and more precisely,
C++/ML-style type-safe-modulo-dynamic-typing exceptions, with
performance comparable to C++ exceptions.
Spawning a task is going to be more expensive than a C++ try-protected
block; there's a private heap and private scheduling (failure is async
relative to the execution of the parent).
I can't pretend the costs are equivalent. It'll be more expensive. But
the intent was for that expense to be the price paid for more-useful
isolation: IME most C++ try-protected blocks fail to actually contain
their error, because the heap is corrupted on the way out.
Aside from the cost angle, yes, I think given an implementation of 'any'
and the appropriate failure-message-conveyance on task failure, we'll
have something that behaves similar to C++ exceptions, but with task
isolation -- more-proper containment. That's why I chimed in initially
on this thread saying "we already have exceptions". That much is on the
drawing board.
IMO this thread is about whether we need something else, in addition,
that *is* as cheap as C++ try-protected blocks, and possibly does
finer-grained recovery (in terms of language abstractions employed). To
me that's not clear yet, and I'm suggesting we err on the side of not
providing it and seeing how the existing abstractions hold up.
And in that case, I have some difficulty finding out exactly which case
remain to be covered by the library design you detail above.
Could you provide a few examples before I answer the following?
Which, the pass-flags-in approach, or reviving the older design for
signals-and-handlers?
-Graydon
_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev