Peter Scott wrote:
> 
> Tony Olekshy wrote:
> >
> >    finally { ... }
> >
> >         Invoked whether or not unwinding.  If the finally block
> >         throws then unwinding starts or continues, if finally
> >         doesn't throw then the unwinding state is not changed.
> >         Inside the finally block, $@ is the last raised exception
> >         if unwinding, and undef if not unwinding.
> >
> >     catch { ... }
> >
> >         Invoked if unwinding.  This is a post-finally catch, but
> >         otherwise it can have all the syntax of other catches.
> >         If the catch block doesn't throw then unwinding stops.
> 
> What's this for?  If the finally block throws?

Actually it's invoked if we're unwinding at that point, according to
the definition of unwinding contained in v0.1.  RFC 88 gives this
example (but it uses "unwind" instead of the final "catch"):

        try     { TryToFoo; }
        catch   { TryToHandleFailure; }
        finally { TryToCleanUp; }
        catch   { throw "Can't cleanly Foo."; };

In our production code we often add such blocks to major API entry
points; that is how we get unwind stack tracebacks like the one
shown in RFC 88:

        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 Company table.
        IOM.5678: Can't open file ".../company.db".
        IOM.6789: Access to ".../company.db" denied.

> > This is (I believe) very similar to RFC 63 syntax, other than
> > [...] throw is not a constructor (you must pass throw a
> > constructed exception, if that's what you want), so people
> > can still say things like throw "Can't open $file.";
> 
> Hmm.  I guess I would do that either with
> 
>      throw Exception(message => "Can't open $file");
> or
>      die "Can't open $file"
> 
> which RFC 63 says (under IMPLEMENTATION) should be the same thing.

Excellent.  So throw is an Exception constructor that does die $self.
If a non-Exception is passed to die, die wraps it up in an Exception.

> > $@ or equivalent contains the current exception (but a linked
> > list of previous exceptions raised since unwinding started is
> > kept via a _link attribute in the Exception objects, which you
> > can ignore except in the case of the "any" method described
> > below, or if you want to generate a formatted unwind stack to
> > show the user).
> 
> You want: while handling an exception, throwing another exception
> pushes the first one onto a stack which could be reported en masse
> when the coup de gras arrives.  Like VMS error cascading.  You do
> this with a _link attribute of exceptions.  Cool, I can dig that.

Yup, as per the traceback shown above.  This is going to become more
important when Perl starts using exceptions for error handling, for
example, if an open throws and a calling DB module throws, and then
your UI catches it, you are (in many cases) going to want to know
why the open threw.

> I want: exceptions to contain 'file' and 'line' attributes which
> are arrays that get a location pushed on every time an exception
> bubbles up through a scoping level.
>
> main.pl:
>    1  try {
>    2    foo($obj);
>    3  };
>    4  sub foo {
>    5    $_[0]->bar();
>    6  }
> 
> Foo.pm:
>  100  sub bar {
>  101    pling(shift);
>  102  }
>  103  sub pling {
>  104    throw Exception::Baz unless blech(shift);
> 
> that by the time the exception percolates to the outermost level,
> the attributes contain:
> 
>          file            line
>          Foo.pm          104
>          Foo.pm          101
>          main.pl         2

I just ran the following code though the Try.pm module referenced
in RFC 88:

    scott1.pl:

        use Try devel => 1;  use scott2;  my $obj = "Test";
        try {
            try {
                foo($obj);
                };
            sub foo {
                bar($_[0]);
                }
            }
        catch {
            print Try::ShowStack(Trace => 1);
            }

    scott2.pm

        use Try;
        sub bar {
            pling(shift);
            }
        sub pling {
            throw "Exception";
            }

And the following output was generated:

    Exception

    $ = Try::throw('Exception') called from scott2.pm[8].
    $ = main::pling('Test') called from scott2.pm[4].
    $ = main::bar('Test') called from scott1.pl[1].
    $ = main::foo('Test') called from scott1.pl[8].
    $ = Try::try(CODE(0xca8830)) called from scott1.pl[9].
    $ = Try::try(CODE(0xca2418), 'catch', CODE(0x10b18ac))
        called from scott1.pl[8].

If I'm not mistaken, exceptions must bubble up through the call
stack as at the point the exception is thrown, so if we capture
that stack traceback then, we have all the info.  Do you still
want the file/line array?

> > If I'm not mistaken, that lets me do everything RFC 88 does, it
> > is more regular and directly extensible, and it still leaves the
> > option for unwind stack formatting via the internal links.
> 
> I can go for that.
> 
> I think we're nearly at a consensus here.

Agreed.  After Wednesday I won't have access to these mailing lists
for ten days (please everyone, hold you applause), but I may have
enough email to be able to work with you on the new omnibus RFC.
I'll contact you independent of this list.

Yours, &c, Tony Olekshy

PS: In another message, Peter asks: if 'try' does an implicit "local
$SIG{__DIE__}" at the beginning of its block, does that not handle
the problem without getting rid of the thing?  I believe so, that's
how RFC 88's Try.pm does it.

Reply via email to