To use a $20 OO word, polymorphism.  But this applies even if
$@ isn't an instance of an OO class, as explained herein.

If die/throw can put any data they want in $@, then before a
exception can be conditionally caught, the value of $@ must be
checked to see if it conforms to the intended check.  For example,
if one user is allowed to die [ ... ]; and another user is allowed
to die { ... }; then catch clauses must be written like this.

    catch ref $@ isa "HASH" && $@->{foo} => { ... }

    catch ref $@ isa "ARRAY" && $@->[0] => { ... }

By placing some minimal structure on $@, say even a hash ref, catch
clauses can always be written like this

    catch $@->{foo} => { ... }

because if any given die/throw doesn't set $@->{foo}, this still
works.  That's a simple kind of polymorphism with a simple hash ref.

Now it takes no great insight that if $@ is going to be a hash ref,
then we can simply bless the hash into some class, say "Exception",
and then hang a bunch of convenience methods off the Exception::
namespace to avoid having a library version of the functions which
would pollute the namespace.  And, it means we can write $@->foo,
instead of something like foo_exception($@), in catch clauses.

There you have it.  That's why RFC 88 uses structured data for $@.

Now, here's an alternative that may keep everyone happy.  In
addition to whatever RFC 88 does now, change this rule about how
die behaves:

    If passed a single argument that isa "Exception", raise it as
    the new exception and die in the fashion that Perl 5 does.

    Otherwise, the arguments are stringified and joined with C<''>
    (as in Perl 5), the resulting string is wrapped up in a new
    Exception object (setting the message instance variable to said
    string), and the new Exception object is raised.

to read like this:

    If passed a single argument that isa "Exception", raise it as
    the new exception and die in the fashion that Perl 5 does.

    Otherwise, the arguments are stringified and joined with C<''>
    (as in Perl 5), the resulting string is wrapped up in a new
    Exception object (setting the message instance variable to said
    string), the original unstringified arguments are saved in a
    list ref in the object's C<args> instance variable, and the new
    Exception object is raised.

then you can say C<die qw(A B C)>, and the following tests both work:

    catch $@->args->[1] eq "B" => { ... }

    catch $@ =~ /B/ => { ... }

Yours, &c, Tony Olekshy

Reply via email to