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