Branden wrote:
> 
> There's something I didn't quite understand about RFC 88:
> 
> When I
> 
>     try {
>         die "foo";
>     } catch {
>         die "bar";
>     }
> 
> I die with "bar", right? But what happens if I
> 
>     try {
>         die "foo";
>     } finally {
>         die "bar";
>     }
> 
> I die with "foo" or "bar"? Why is this the right behaviour? Any
> sample code that shows why this should be done this way and not
> the other?

I both cases, since the "foo" exception is not cleanly caught by
either example, unwinding will be propagated at the end of the try
statement.  The code in catch and finally clauses of any outer try
clause (one "containing" the above examples, but not necessary in
the same lexical scope) will see the following:

    $@[0] eq "bar" and $@[1] eq "foo" and $@ = $@[0]

with the proviso that the items in the @@ list are actually
exception objects that stringify back to the message passed to die.

In other words, RFC 88 maintains in @@ a stack of all exceptions
raised while in the process of handling and propagating unwinding,
with new exceptions unshifted to occupy $@[0] when they occur.  This
stack is only cleared when exception handling cleanly catches (that
is, a catch clause matches and completes without itself raising an
exception).

Two useful results arise from this technique.

 1) In a catch block, print join("\n", @@), "\n"; effectively
    generates an exception stack traceback.  In fact, RFC 88 allows
    you to say $@->show with that effect, and supports options for
    including things like showing the Perl stack traceback as at the
    raising of the first exception (the one in $@[-1]), showing
    exeption class names, and/or showing other debug information
    only to developers and log files, but not to end users.  That's
    how it generates messages like this

        UIM.1234: Can't add a new person to the database.
        APP.2345: Can't update Company relationship.
        DBM.3456: Trouble processing SQL UPDATE clause.
        DBM.4567: Unable to write to Locations table.
        IOM.5678: Can't open file ".../locations.ndx".
        IOM.6789: File ".../locations.ndx" not found.

    which I referred to in
    http:[EMAIL PROTECTED]/msg05799.html

 2) In the test expression in a conditional catch clause, you can
    operate on the entire @@ stack.  For example,

    try { ... } catch grep { $_->isa("Foo") } @@ => { bar(); }

    will call bar() only if the try block unwinds *and* any of the
    exceptions involved in the unwinding are instances of a class
    that inherits from Foo.

    Similarly, the following two clauses

        catch grep { ref $_ =~ /Alpha/ } @@ => { ... }
    and
        catch grep { $_ =~ /Beta/ } @@ => { ... }

    match only if any exception class name matches Alpha, or any
    exception's message string matches /Beta/, respectively.
    You can also test other exception object properties with
    tests of the form

        catch grep { $_->{tag} eq "XXX.1234" } @@ => { ... }

    Of course, if you're only interested in the most recent
    exception, skip the grep operations in these examples and
    just test $@ directly (which works because of the rule that
    $@ is always equal to $@[0]).

Both of the above results are implemented in the RFC 88 Perl 5
reference implementation (modulo syntax).  There are more examples
at http://www.avrasoft.com/perl6/rfc88.htm#Examples

Yours, &c, Tony Olekshy

Reply via email to