At 06:10 AM 8/17/00 -0600, Tony Olekshy wrote:
>    catch "Error::DB" { ... }
>
>     catch [ "Error::DB", "Error:IO" ] { ... }
>
>     trap { $@->{message} =~ /divide by 0/ } catch { ... }

I don't think you need another keyword here.  Just support an expression 
argument to catch and you can do

     catch $@->{message} =~ /divide by 0/  { ... }

If it needs to be more complicated, use 'do'; that should still make it 
parseable.  At the very worst it may need a comma the way map uses it, 
which we can write as =>.  But I don't think that'll be needed.

Note: I used to favor $_[0] for the exception, but I'm being won over to 
$@.  As long as it doesn't cause problems with external interfaces.  Might 
mention the $_[0] idea in a footnote.

>     catch { ... }
>
>     finally { ... }

Still want this to be "continue"; let's mention both.

>Any exceptions that are raised within an enclosing try, catch, trap,
>or finally block (anywhere up the subroutine call stack) are trapped
>and processed according to the semantics described in this RFC.

Maybe it's just me, but I think of 'up' the stack as being my callers, and 
'down' being my callees.

>The new built-in Exception base class is designed to be used by Perl
>for raising exceptions for failed operators or functions, but this
>RFC can be used with the new base class whether or not that happens.
>
>=head1 DESCRIPTION
>
>exception 'Error::DB::Foo';
>
>     Makes Error::DB::Foo into a class that behaves like a built-in
>     Exception.
>
>     If the given name matches /::/, something like this happens:
>
>         @Error::DB::Foo::ISA = 'Error::DB';
>
>     If the given name does not match /::/ (say it's just 'DB'), this
>     happens instead:
>
>         @DB::ISA = 'Exception';

I think you want to s/Error/Exception/ above.  Then the rule is 
simpler.  Require all exceptions to be subclasses of 'Exception' for clarity.

>throw Error::DB => "a message", tag => "ABC.1234", ... ;

Suggest dropping the =>.  Then throw can be implemented as an object method 
and this is just the indirect object syntax.  Do you really want to leave 
out the "message =>" there?  IMHO it looks confusing to tie the class to 
the message and leave the message attribute name out.  So I suggest

   throw Error::DB (message => "a message", tag => "ABC.1234");

except that my vote is for "code" instead of "tag".

>     Syntactic sugar for:
>
>         die Error::DB->new(
>
>                 message => "a message", tag => "ABC.1234", ...);
>
>     A throw with no arguments is syntactic sugar for re-raising
>     the current exception.  If there is no current exception,
>     an anonymous Exception is manufactured first.

Um, I don't like that.  What's an anonymous Exception?  What would its 
attributes be?

I think it's easier to require them to "throw $@" if they want to rethrow, 
so you're not forced into this anonymous exception thing.

>catch { ... }
>
>     Traps all exceptions, according to the unwind semantics
>     described below.
>
>     It is a syntax error for a catch all clause like this to be
>     immediately followed by a trap clause or another catch clause.
>
>     Otherwise, it is semantic sugar for trap { 1 } catch { ... }.

AFAIK, only syntax is sweetened.  Semantics are inherently low-cal.

>catch "Error::DB" { ... }

I want to be able to drop the quotes.  With 'catch' being a full-blown 
keyword, this is possible.

>trap { ... } catch { ... }
>
>     Traps exceptions for which the trap block returns true.
>
>     It is a syntax error if the catch clause following a trap
>     clause has a scalar before its block.

You won't have that loophole to close with the catch EXPR option.

>die
>
>     If argument isa "Exception", raise it as the new exception and
>     die in the fashion that Perl 5 does.
>
>     If argument isa "UNIVERSAL", wrap it in a new Exception (using
>     the "object" instance variable), and raise that instead.

Hmm... what is the benefit of being able to throw objects that aren't 
exceptions?

>    When an exception $e is raised, the following is automatically
>     done:
>
>             $e->{link} = $@;  $@ = $e;

Only if $@ was defined, I presume.

>   1. Whenever an exception is raised Perl looks for an enclosing
>      try/catch/finally block.
>
>      If such a block is found Perl traps the exception and proceeds
>      as per rule 2, otherwise program shutdown is initiated.

I wonder if we should anticipate the possibility of $SIG{__DIE__} 
surviving... and saying that at this point it could get its horny little 
hands on the exception.

>=head2 Built-In Exception Base Class
>
>In addition to the built-in Exception class described below, a
>built-in Error class is defined.  The Error class inherits from
>Exception.  Internal Perl assertion failures are instances of
>exception classes that inherit from the Error class.  This
>results in code like C< catch "Error::IO::File" { } >.  It
>also allows simple anonymous error exceptions to be raised with
>a form like this:
>
>     throw Error => "message", severity => "Fatal";

I don't see what you mean by 'anonymous' here.  I also think there should 
be exactly one exception class hierarchy.

>trace
>
>     A listref containing a snapshot of the call-stack as at the time
>     the exception is first raised.  The array contains hashes (one
>     per call stack level), each containing one key value pair for
>     each snapshot value at that level.  Here are some examples:
>
>             $e->{trace}->[0]->{file}
>             $e->{trace}->[0]->{line}
>             $e->{trace}->[0]->{sub}
>
>     This snapshot is set up by the "snapshot" method, so that
>     derived classes that don't want this overhead can override
>     the method.

I know I was pushing for this, but Ive seen the light that in fact caller() 
should be doing this for us.  Can you see any reason that won't do?

>overload '""' => sub {
>
>     my $t = exists $_[0]->{tag} ? $_[0]->{tag} . ": " : "";
>
>     exists $_[0]->{severity} and $t .= "($_[0]->{severity}) ";
>
>     $t .= $_[0]->{message} =~ /\S/
>         ? $_[0]->{message} : "anonymous exception.";
>     }

I think we should just be defining semantics here, not supplying code.

>=head1 EXAMPLES
>
>The following three examples conver the most common uses of try,
>catch, and finally.
>
>     open(*F, ">foo");  try { ... } finally { close F; }

Why isn't the open inside the try block?  Don't you want to see if it 
succeeded?

See my earlier comments about all linked blocks sharing the same lexical 
scope, btw.

>Keyword Names
>
>     RFC 88 only introduces the try, throw, trap, catch, finally,
>     and exception keywords, which are all traditionally related
>     to exception handling.  Also, "try" was chosen because of it
>     neutral connotation (unlike "fail" for example), because
>     exceptions do not necessarily encapsulate a negative.

I think throw and exception only need to be functions.

>    because the author is of the opinion that overloading else and
>     continue with unwind semantics not traditionally associated with
>     else and continue can be confusing, especially when intermixed
>     with local flow-control forms of else and continue, or when
>     an "else throw" is forgotten on a switch that needs to re-throw.
>
>     The "try" is not necessarily for Perl's sake.  It's for the
>     programmer's sake.  It says, watch out, some sort of non-local
>     flow control is going on here.  It signals intent to deal with
>     action at a distance (unwinding semantics).

Well said.

>    How to arrange the exception class hierarchy for the Perl core?

This is the province of RFC 80.  I can just remove the stuff that's already 
been subsumed in this draft.


--
Peter Scott
Pacific Systems Design Technologies

Reply via email to