This and other RFCs are available on the web at
http://dev.perl.org/rfc/
=head1 TITLE
Change the way $SIG{__WARN__} and $SIG{__DIE__} are used
=head1 VERSION
Maintainer: Chris Hostetter <[EMAIL PROTECTED]>
Date: 15 Sep 2000
Mailing List: [EMAIL PROTECTED]
Number: 236
Version: 1
Status: Developing
=head1 ABSTRACT
The current method in which C<__WARN__> and C<__DIE__> signal handlers are
used is limited in 2ways:
=over 8
=item It does not allow them to accept robust parameter lists.
=item It does not allow for multiple layers of handlers.
=back
=head1 DESCRIPTION
=head2 Parameter Treatment
The current behavior of C<warn> and C<die> is to first concatenate the
parameter LIST into a single string, before checking if there is a
user specified signal handler. Then pass that string as a single
argument to any handler if it exists.
I propose, that a registered signal handler for C<__WARN__> or C<__DIE__>
should be passed the exact same LIST of arguments that the
corresponding warn or die call received. This would allow complex
programs to use the warn/die signal handling mechanism to for dealing
with complex exception handling, and still recognize low level
warnings / errors from the interpreter.
For example: It is reasonable when developing a large system to want a
mechanism for dealing with "error levels" -- one such approach would
be something like the following...
# use this function EXCLUSIVELY in your code for dealing with
# warnings or errors so that the appropraite acction is taken
sub errorHandle {
my $level = shift;
my @msgs = @_;
if ($config{abort_level} < $level) {
die "Fatal Error ($level): ", @msgs;
}
if ($config{warn_level} < $level) {
warn "Warning ($level): ", @msgs;
}
if ($config{log_level} < $level) {
# log something about @msgs
}
# etc ...
}
# want to make sure we catch things from interpreter and
# code from CPAN
$SIG{__WARN__} = sub { &errorHandler(9, @_); }
$SIG{__DIE__} = sub { &errorHandler(11, @_); }
# ...
&validateSomething($someArg) or errorHandle 9, "couldn't validate";
The problem with this, is that it requires you to use the non standard
"errorHandle" function explicitly in your code. If you are writing a
module that you plan on distributing to others, this is not ideal.
This would be far better, but would require that C<$SIG{__WARN__}>
(and C<$SIG{__DIE__}>) received the same list of parameters that warn (and
die) received...
# want to make sure we catch things from our code, the
# interpreter, or code from CPAN
$SIG{__WARN__} = sub {
my $level = $config{default_warn_level};
(1 < scalar(@_)) ? $level = shift;
my @msgs = @_;
if ($config{abort_level} < $level) {
die "Fatal Error ($level): ", @msgs;
}
if ($config{warn_level} < $level) {
warn "Warning ($level): ", @msgs;
}
if ($config{log_level} < $level) {
# log something about @msgs
}
# etc ...
}
$SIG{__DIE__} = sub { warn $config{default_warn_level}, @_; }
# ...
&validateSomething($someArg) or warn 9, "couldn't validate";
=head2 Nested Handlers
Currently, if a handler is called to deal with C<$SIG{__WARN__}> or
C<$SIG{__DIE__}> then the handler is disabled to prevent infinite
recursion if the handler itself calls C<die> or C<warn>.
It seems only logical, that if the current handler has been localized,
and overshadows an outer handler, then calling C<warn> or C<die> should
invoke the outer handler -- not the real C<warn> or C<die>. For example...
#!/usr/local/bin/perl -w
$SIG{__WARN__} = sub { print "outer handler: ", @_; };
sub bar {
warn "in bar";
}
sub foo {
local $SIG{__WARN__} = sub { warn "foo: ", @_; };
&bar();
}
&foo();
... this script causes "C<foo: in bar at warn.test.pl line 6.>" to be
written to standard error. I propose that "C<outer handler: foo: in bar
at warn.test.pl line 6.>" is more logical output.
This would allow modules to do their own C<__WARN__> and C<__DIE__> handling,
but still propagate the messages out to an application specific
handler.
=head1 IMPLEMENTATION
Unknown.
=head1 REFERENCES
Programming Perl, 2nd Ed -- p139
Programming Perl, 2nd Ed -- p157
Programming Perl, 2nd Ed -- p241