On Sat, Oct 20, 2012 at 11:16 AM, James Boyden <j...@jboy.me> wrote:

> On Sat, Oct 20, 2012 at 10:48 AM, Graydon Hoare <gray...@mozilla.com>
> wrote:
>
> > Some references to the lurking plan here:
> > https://mail.mozilla.org/pipermail/rust-dev/2011-November/000999.html
>
> Firstly, I'd like to express my appreciation for the clear reasoning
> in this linked post.
>
> I found the arguments clear and compelling, matching my own experience
> -- especially the enumeration of the small set of realistic uses of
> exception handling (ignore, retry, hard-fail, log, or try one of a
> small number of alternatives to achieve the desired result).
>
> >   - Condition.raise is a normal function and does something very simple:
> >     - look in TLS to see if there's a handler
> >     - if so, call it and return the result to the raiser
> >     - if not, fail
> >
> >   - This means condition-handling happens _at site_ of raising. If
> >     the handler returns a useful value, processing continues as if
> >     nothing went wrong. It's _just_ a rendezvous mechanism for an
> >     outer frame to dynamically provide a handler closure to an inner
> >     frame where a condition occurs.
>
> This all seems reasonable after reading that post.
>
> > So: API survey. Modulo a few residual bugs on consts and function
> > regions (currently hacked around in the implementation), I have 3
> > different APIs that all seem to work -- which I've given different names
> > for discussion sake -- and I'm trying to decide between them. They
> > mostly differ in the number of pieces and the location and shape of the
> > boilerplate a user of the condition system has to write. My current
> > preference is #3 but I'd like a show of hands on others' preferences.
> <snip>
> > Opinions? Clarifying questions?
>
> I prefer option #3.
>
> I like that it states the condition and handler up-front (in contrast
> to most exception-handling syntaxes, that leave you guessing what
> might go wrong until you reach the catch statements at the end of the
> try/catch block).
>
> I like that the error-handling code is implicitly not an afterthought.
> (I find that when I'm writing the code on the main path, there's a
> strong temptation to just "keep on coding", and come back to insert
> the error-handling code "later".)
>
> I like that it has the minimum of boilerplate code (in contrast to
> option #1 especially).
>
> In addition to the boilerplate, I don't really like option #1 because
> of the separation of the protected block from the handler code.
>
> My concern with option #2 is that, despite my general fondness for
> RAII, the '_g' variable isn't explicitly used anywhere, so creating a
> named variable seems redundant.
>
> Plus, having an object that can reach out of its variable and affect
> all the code that follows in its block scope is too "magical" for my
> liking.
>
> jb
> _______________________________________________
> Rust-dev mailing list
> Rust-dev@mozilla.org
> https://mail.mozilla.org/listinfo/rust-dev
>

This seems heavily influenced by Lisp's Conditions & Restarts[1] (not that
I have used Lisp before though, but I *am* interesting in error handling
strategies), however it seems relatively unclear to me how the syntax work.
If I understood correctly there are 3 steps:

 - declare the condition
 - setup the handler for that condition (with the poll going on)
 - raise a signal for that condition

At the moment you only show the first 2, and it's unclear to me exactly how
the handler is *used* at the call site (looks to me like a regular function
call passing an instance of T as argument and getting a U in exchange). I
suppose it would something like:

    let u = core::condition::signal(OutOfKitten, t)


One of the point I find "difficult" about this (and which is as difficult
with exceptions, short of going the path of the damned with exceptions
specification) is that it might become difficult to know exactly which
handlers to setup; as such this:

  - Condition.raise is a normal function and does something very simple:
    - look in TLS to see if there's a handler
    - if so, call it and return the result to the raiser
    - if not, fail

might be a little forceful.


As such, I would have a tiny request:

=> Would it make sense to just make it a "point of customization" but have
a way to specify a default result in case there is no handler, or even
specify a default handler ?

This means 2 or 3 different flavors of "raising a condition", which adds to
the complexity of the language though. On the other hand, using the syntax
I used above, it's just:

    let u = core::condition::signal(OutOfKitten, t) // default behavior, ie
fail if no handler


    let u = core::condition::signal(OutOfKitten, t, |t| { fail }) //
default behavior made explicit

    let u = core::condition::signal(OutOfKitten, t, |t| { if t == 0 then
fail else 3 }) // custom handler, if none setup

    let u = core::condition::signal(OutOfKitten, t, 4) // simple way to
pass a default return value without actually having to write up a lambda,
ala |t| { 4 }  (just to avoid boilerplate really)


As for the poll, like the others I prefer #3 too. #2 is *definitely* one
weird cookie. And it seems weird to give names to things that are not
invoked through this name later on... (typical issue with RAII)

-- Matthieu


 [1]:
http://www.gigamonkeys.com/book/beyond-exception-handling-conditions-and-restarts.html
_______________________________________________
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev

Reply via email to