RFC 88 is discussing making errors into exceptions.  I strongly
don't think we should attempt the converse, that is, making
exceptions into errors.

    "An exception is not necessarily an error.\n" x 3;

That's why RFC 88 defines both Exception and Error classes, the
latter of which inherits from the former.  Common usage will be
via Error, while still allowing for other non-error kinds of
exceptions.

Here at work we have algorithms that depend on throwing a
rather large number of light-weight exceptions for the purpose
of indicating exceptions that are not errors, but are non-local
flow-control success gotos for an MVC architecture.  The cost
of capturing the stack traceback (for example) for every such
exception would be prohibitive to us.  If RFC 88 leaves the
stack capturing problem to Error, then we can just use Exception
for what we need.

On the other hand, this means that if we require the exception
class hierarchy to be exposed in the class name, everyone will
have to write Exception::Error::Foo, when they really just want
Error::Foo.  Therefore, RFC 88 allows exception classes of the
form:

    package MyException;

    @MyException::ISA = 'Exception';

in addition to

    package Exception::MyException;

    @Exception::MyException::ISA = 'Exception';

This also means it is possible to define exception classes such
as Error_UI (that inherit from Error::App, for example), using

    exception Error_UI isa => Error::App;

instead of requiring one to always have to always write, for
example, Exception::Error::App::UI.  It's 8 characters or 25.

It is the intention of RFC 88 that all core Perl errors will
be instances of classes that inherit from Error, but not
instances of the class Error itself.  This leaves Error itself
free for other use. RFC 88 envisions using Error itself for
throwing simple errors that the developer does not wish to
have to categorize into a class taxonomy, like this:

    throw Error "Can't foo.";

We could just say that C<die "Can't foo."> creates an Error
object, but I'd still rather write the former because it
is self-documenting.  Besides, C<die "Can't foo."> should
raise an Exception, not an Error (because an exception is
not necessarily an error), but in the example above I want
an Error, not an Exception.

Peter Scott wrote:
> 
> Why not Exception::IO::File::Open?  Why do you want this
> hierarchy called Error?

The instance variables and methods supported by Exception should
be just those required to make the exception handling mechanism
work.  The Error class should add/override the instance
variables and methods that are needed to make error handling via
exceptions work.  This means that error handling overhead need
not come into play for those who wish to use exceptions for
other purposes.

> > throw MyDB "ABC.1234: Some message about what went wrong.";
>
> Your simple case doesn't have the word Exception in it
> anywhere, which I think is a big visual marker; MyDB is a
> subclass of it, right?

You are right, that's a bad example.  I should have written

    throw Error_DB "ABC.1234: Some message.";
or
    throw Error::App::DB "ABC.1234: Some message.";

If one prefers the latter that's fine, RFC 88 doesn't mandate
either way.  But I don't want to *have* to write the following:

    throw Exception::Error::App::DB "ABC.1234: Some message.";

To put it another way, throw is defined to have a first argument
that names an Exception class or is an Exception object.  Once
you've used throw for a day, you know that.  Why would one want
to be *required* to always repeat that information in the name?

> > @Error::DB::Foo::ISA = 'Error::DB';
> 
> Hmm, suppose they haven't done "exception 'Error::DB'"?
> Should it create that for them?

Added to RFC 88v2d3.  It will throw if it finds a parent class
that already exists and is not an Exception.

> >Exceptions raised by the guts of Perl are envisoned by this
> >RFC to all be instances of classes that inherit from Error.
> 
> That's orthogonal to this RFC, though.  You can propose an
> exception handling mechanism without requiring that the core
> use it; that's what RFC 80 is for.

Right. That's why RFC 88 says:

    The new built-in Error 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 Exception
    and Error base classes whether or not that happens.

RFC 88 defines try/throw/catch/finally and the base Exception
class for exception objects they expect to operate on.  It also
defines the concept of an Error class, which inherits from
Exception, to be used when handling errors via the exception
handling mechanism.  The details of the Error class are the
province of RFC 80 or others, the fact that it inherits from
Exception is the only thing RFC 88 cares about.  I'll try
to be more clear in v2d3 when I'm talking about "suggested"
behaviour for Error, rather than sounding like I'm sugggesting
it's required.

> >Instances of the actual Error class itself are reserved for
> >so-called anonymous exceptions, for those cases in which one
> >more or less just wants to say C<throw Error "My message.">,
> >without a lot of extra tokens, and without getting into
> >higher levels of the taxonomy of exceptions.
> 
> This is what the user would get by just die-ing.  Let's not
> use 'anonymous'; it makes people think of anonymous arrays,
> hashes, & subroutines, and hence confused.

I'll expunge "anonymous".  We still have C<die Error->new;> to
deal with though.  How 'bout if we call such un-subclassed,
un-parameterized cases "simple" exceptions.

> >Although this Exception/Error partitioning has not yet been taken
> >advantage of in this RFC, it does provide a good place to help
> >make exception handling and error handling into almost the same
> >thing, without adversely affecting the functionality of either.
> 
> I think this is unnecessary (and we should shorten the RFC so
> that more people will read it).  Leave the whole Error class
> out; that's something separate, as I've said.  I can make RFC
> 80 say what you want system exceptions to be.

Well, the partitioninig is about to be taken advantage of, in
88v2d3, by explicitly referencing RFC 80 as the "owner" of the
Error class, independent of the fact that RFC 88 expects it
to inherit from Exception.

> > The built-in Exception class reserves all instance variable
> > and method names matching C</^[_a-z]/>.  The following
> > instance variables are defined.
> >
> >tag
> >severity
> >message
> >debug
> >object
> >sysmsg
> >trace
> 
> Why sysmsg?  Why wouldn't a core exception use message?
> Why should someone have to look at both?

The message ivar is for the "end user" message.  The debug ivar
is for additional non-end-user information (for example, in a
web app, internal file names might be considered sensitive
information, but you would still like to get the name of the
file that couldn't be opened into the server log).  These ivars
are part of Exception.

The sysmsg ivar is properly the province of the Error class and
RFC 80, which may want to actually introduce a structured value
here, since $!, $?, and $^E have to all be accounted for.

> Technically, the only ones of these that impact the core are:
> message, and link.  The others might be better broken out into
> another RFC.  One RFC for throwing and handling exceptions;
> another one for what goes in the exceptions.

Link is toast, given @@.  The tag ivar is also in, because of
the namespace managing stuff.  The object ivar is required for
wrapping non-Exception objects (if we keep that functionality
in, otherwise I'd still like to leave it in for Exceptions
that "relate-to" and object).  And while severity and trace are
not strictly required by Exception, it seems reasonable to leave
them stubbed in for polymorphism across Errors and Exceptions.

Yours, &c, Tony Olekshy

Reply via email to