This and other RFCs are available on the web at
  http://dev.perl.org/rfc/

=head1  TITLE

Merge C<$!>, C<$^E>, C<$@> and C<$?>

=head1  VERSION

      Maintainer: Peter Scott <[EMAIL PROTECTED]>
      Date: 25 Aug 2000
      Last Modified: 13 Sep 2000
      Mailing List: [EMAIL PROTECTED]
      Number: 151
      Version: 3
      Status: Developing

=head1  ABSTRACT

The distinction between the C<$!>, C<$^E>, C<$@> and C<$?> variables is no 
longer worth trading for the benefits to be gained from merging them together.

=head1  DESCRIPTION

The C<$!> variable made excellent sense in Perl 4 as a representation of 
the Unix C RTL C<errno>.  It went right along with the tight integration 
and close mapping between Perl and sections 2 and 3 of the Unix manual.

The amount of third-party code published via CPAN made possible by the 
module features of Perl 5, and the likelihood of exception handling gaining 
increased importance in Perl 6 both serve to make the distinction between 
errors for which C<$!> is set and those it isn't, less useful.

Non-system code throws exceptions by C<die>ing and any code that handles 
those exceptions reads the reasons in the C<$@> variable.  Why have two 
classes of errors where failure reasons are passed in different variables 
when the distinction between those classes may appear irrelevant (not a 
Unix platform) or arbitrary (what is a "system error" and why should it be 
set for a failed C<open> but not, say, for a failed C<new IO::Socket>?)?

Hence this proposal is to merge all these together into a single 
out-of-band indicator of error, so that users don't have to check multiple 
variables in the case of an C<eval>.

=head1  IMPLEMENTATION

Merge all these variables into one.  Say for the sake of argument that it 
is C<$!> (for the mnemonic value of "something went bang").  This variable 
will I<always> be an object.  An attribute will determine whether it is 
something that can be caught or could cause a C<die>; this will be checked 
by code implementing exception handling (like, say, RFC 88).  Call this 
attribute C<is_exception> for the sake of argument.

It should be possible to make the same attribute fulfil and extend the 
requirement of RFC 70 to make C<Fatal.pm> applicable throughout the core 
and optionally to user modules.

Note that if RFC 88 passes, it requires C<$@> to become a structured object 
anyway; this RFC simply proposes using the same object for other errors as 
well.

What about situations where more than one of the current set of four 
variables might be set?  Well, note that C<$^E> is just an extension of 
C<$!>, so we can consider those two variables collapsed into C<$!>.  The 
following cases obtain:

    Perl would    |    The error variable is currently
    currently set |Non-existent: |Existent, and is_exception is
                  |create new one|    true      |    false
                  |setting its   |              |
                  |is_exception  |              |
    ==============|==============|==============|===============
        $!, $^E   | Depends on   | Overwrite,   |
                  | Fatal.pm     | but see      |
                  | applicability| discussion   |  Overwrite
    --------------+--------------+ below        |
         $?       | False        |              |
    --------------+--------------+--------------+---------------
         $@       | True         | New one links| New one links
                  |              | to previous  | to previous
                  |              | per RFC 88   | via sysmsg

The one case that needs special attention is (assuming RFC 88 passes) when 
the variable is holding a current exception and a non-exception error 
occurs.  Furthermore, the only place this is a problem is C<catch> and 
C<finally> blocks (see RFC 88).  It cannot occur in a C<try> block because 
as soon as anything would create an exception, it will cause control to 
leave the C<try> block.

In a C<catch> block, the exception is to be cleared at the end of the block 
anyway so overwriting it with a non-exception error would not cause a 
problem for control flow.  In a C<finally> block, any current exception 
needs to be preserved at the end of the block, therefore it cannot be 
overwritten; but Perl could save the exception on entry to the C<finally> 
block and restore it on exit.  The one remaining issue is how the user can 
access the current exception in a C<catch> or C<finally> block after a 
non-exception error.  In this arguably rare case, they could get it from 
the first element of the
C<@@> array, which RFC 88 defines as the exception stack.

To expand upon parts of the above table:

After a failed C<system>, C<``> or anything else that currently sets C<$?>: 
the variable will be created with the C<is_exception> attribute false.  In 
a numeric or string context, the variable will be the number that would 
currently be placed in C<$?>.  If the variable already existed, then if 
C<is_exception> was false, it is overwritten, otherwise see the discussion 
above.

On a failed system call (something that currently sets C<$!>; not a 
C<system> call): the variable will be created with the C<is_exception> 
attribute false.  The value of the variable in numeric and string contexts 
will be the same as what would currently be placed in C<$!>.  Where the 
C<$^E> variable would currently be set, set a C<extra_info> attribute or 
some such.  (We could actually use the C<sysmsg> attribute, but that might 
confuse people traversing linked errors who expect that always to be a 
reference or undef.)  If the variable already existed, then if 
C<is_exception> was false, it is overwritten, otherwise see the discussion 
above.

On a C<throw> or C<die>: the variable will be created with the 
C<is_exception> attribute true.  If the variable previously existed with a 
C<is_exception> value of false, a link to the previous value will be 
provided in the C<sysmsg> attribute.  RFC 88 details how and under what 
circumstances the variable is linked to a previous version which had 
C<is_exception> true.


=head2 Impact on RFC 88

If the variable chosen is C<$@>, no impact.  If the variable chosen is 
C<$!>, then C<$@> needs to be changed to C<$!>.  The implementation of RFC 
88 will need to check not merely for the existence of the error variable 
but whether its C<is_exception> attribute is set to know whether there is a 
current exception.


=head1  REFERENCES

L<perlvar/"Error Indicators">

RFC 88: Structured Exception Handling Mechanism (Try)

RFC 80: Exception objects and classes for builtins

RFC 70: Allow exception-based error reporting

Reply via email to