Mailing List Archive

$SIG{__DIE__} (was Re: Over-zealous warnings ignore eval)
On Wed, 30 Aug 1995, Larry Wall wrote:

> : % perl -le 'print "here"; eval q(a "b"); print "there"'
> : here
> : String found where operator expected at (eval 1) line 1, near "a "b""
> : (Do you need to predeclare a?)
> : there
>
> $SIG{__WARN__} was construed as a fix for this, or at least a workaround.
> It's hard to know how best to handle this in the general case. The current
> default is to err on the side of providing too much information rather
> than too little.

That reminds me of something else. I just tried using $SIG{__DIE__}, but
I must say that the behaviour isn't too helpful in my case. It always
appends the line and file info (if no LF.) I was hoping that I could
override this.

Spefically, in working on the POD stuff, it would be great if:

die "L<...> may not contain nested commands";

could be turned by $SIG{__DIE__} into:

die "L<...> may not contain nested commands near line $line of $ARGV.\n";

Unfortunately, it seems that just can't be done right now.

--
Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
>From: Kenneth Albanowski <kjahds@kjahds.com>
>
>That reminds me of something else. I just tried using $SIG{__DIE__}, but
>I must say that the behaviour isn't too helpful in my case. It always
>appends the line and file info (if no LF.) I was hoping that I could
>override this.

You must be missing something. You have to leave the subroutine with a
goto or exit. Assign @_ to a variable, process it in perl, and voila'.

>
>Spefically, in working on the POD stuff, it would be great if:
>
> die "L<...> may not contain nested commands";
>
>could be turned by $SIG{__DIE__} into:
>
> die "L<...> may not contain nested commands near line $line of $ARGV.\n";

your line number is in $. isn't it? Here is what I use:

{
local $SIG{__DIE__} = sub { do_log("VERRRY Bad URL: $uri: @_"); goto RETURN; };
unless ($uri_obj = new URI::URL $uri, $Config->{INCOMING}){
do_log("Bad URL: $uri");
return;
}
}
RETURN: return;

>
>Unfortunately, it seems that just can't be done right now.

I doubt :)

>
>--
>Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)
>
>
andreas
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
On Thu, 31 Aug 1995, Andreas Koenig wrote:

> You must be missing something. You have to leave the subroutine with a
> goto or exit. Assign @_ to a variable, process it in perl, and voila'.

Agreed, it's just that the voila' in question isn't quite the voila' I need.

> > die "L<...> may not contain nested commands near line $line of $ARGV.\n";
>
> your line number is in $. isn't it? Here is what I use:

No, not in this case. I'm reading in paragraphs at a time, and the
defaults aren't of much use.

> {
> local $SIG{__DIE__} = sub { do_log("VERRRY Bad URL: $uri: @_"); goto RETURN; };
> unless ($uri_obj = new URI::URL $uri, $Config->{INCOMING}){
> do_log("Bad URL: $uri");
> return;
> }
> }
> RETURN: return;
>
> >
> >Unfortunately, it seems that just can't be done right now.
>
> I doubt :)

Yes, but you are using "do_log", not die, and you aren't worring about \n.
Here's what I tried:

$SIG{__DIE__} = sub {
die "(nonl) @_ near line $line of $ARGV\n" if substr("@_",-1,1) ne "\n";
die "(withnl) @_";
cancel;
};

die "foo";

This _appears_ to be the obvious way to do this sort of thing. The only
problem is that it doesn't work. The "at $ARGV line $." is tucked onto @_
before you get a say in things.

> >Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)
> >
> andreas
>

--
Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
>From: Kenneth Albanowski <kjahds@kjahds.com>
>Yes, but you are using "do_log", not die, and you aren't worring about \n.
>Here's what I tried:
>
>$SIG{__DIE__} = sub {
> die "(nonl) @_ near line $line of $ARGV\n" if substr("@_",-1,1) ne "\n";
> die "(withnl) @_";
> cancel;
>};
>
>die "foo";

Kenneth,

I think I understand what you mean, and I think I have a
solution. Whereas I use $SIG{__DIE__} to workaround the croak()s and
die()s in the LWP library, you try something completely different.

But as you describe the problem, you seem to be free to call whatever
you want in your functions and methods. If you do not call die(), you
do not need to use $SIG{__DIE__}.

Can't your example

>Spefically, in working on the POD stuff, it would be great if:
>
> die "L<...> may not contain nested commands";
>
>could be turned by $SIG{__DIE__} into:
>
> die "L<...> may not contain nested commands near line $line of $ARGV.\n";
>
>Unfortunately, it seems that just can't be done right now.

easily be solved by calling

myerrorhandler("L<...> may not contain nested commands");

instead?

IFF you want to catch a foreign die() and you don't know, if the die()
will come with or without " at filename line nnn." tacked (sp?) on @_,
then you can apply this substitution (messy but correct, I think):

$SIG{__DIE__}=sub {
# tested with very weird filenames with newlines and metacharacters embedded
my($message) = @_;
print "message [$message]\n";
@caller=caller;
$message =~ s/ at \Q$caller[1]\E line $caller[2]\.\n//s;
print "message [$message]\n";
die "bar";
};

I agree, that this is not the most elegant approach. Basically I undo
what the die() code did. But I think, it does what you want. Do you
have an imagination how you would like the $SIG{__DIE__} interface?
Maybe you would prefer that the $SIG{__DIE__} subroutine is called
with 3 arguments instead of one?

$SIG{__DIE__} = sub {
my($message,$file,$line) = @_;
}

????

>Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)

andreas
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
On Fri, 1 Sep 1995, Andreas Koenig wrote:

> Kenneth,
>
> I think I understand what you mean, and I think I have a
> solution. Whereas I use $SIG{__DIE__} to workaround the croak()s and
> die()s in the LWP library, you try something completely different.

Quite right.

> Can't your example
> [...]
> easily be solved by calling
>
> myerrorhandler("L<...> may not contain nested commands");
>
> instead?

Yes, it can, but to my mind this is discarding one of the points of having
$SIG{__DIE__} in the first place. die() normally knows about line numbers
and files, and will automatically append that information. In the code
environment I'm working in, files are loaded by paragraphs, and thus the
defaults really doesn't work quite well enough. I'd much prefer to use a
real die(). (Not to mention the fact that with die(), warn(), croak(),
carp(), and whatever other warning mechanisms there are, it's much easier
to remember just die(). ;-)

> IFF you want to catch a foreign die() and you don't know, if the die()
> will come with or without " at filename line nnn." tacked (sp?) on @_,
> then you can apply this substitution (messy but correct, I think):
>
> $SIG{__DIE__}=sub {
> # tested with very weird filenames with newlines and metacharacters embedded
> my($message) = @_;
> print "message [$message]\n";
> @caller=caller;
> $message =~ s/ at \Q$caller[1]\E line $caller[2]\.\n//s;
> print "message [$message]\n";
> die "bar";
> };

Yes, that would do it. And yes, this isn't very elegant.

> I agree, that this is not the most elegant approach. Basically I undo
> what the die() code did. But I think, it does what you want. Do you
> have an imagination how you would like the $SIG{__DIE__} interface?

My original idea (back when I suggested $SIG{__DIE__}) was that only an
actual die() would append the " at X line Y." data, and the $SIG{__DIE__}
routine would never see it. Larry took the opposite tack and it gets
appended before $SIG{__DIE__} is invoked.

> Maybe you would prefer that the $SIG{__DIE__} subroutine is called
> with 3 arguments instead of one?
>
> $SIG{__DIE__} = sub {
> my($message,$file,$line) = @_;
> }
>
> ????

I'd say:

$SIG{__DIE__} = sub {
my($message,$append) = @_;
}

where $append is whatever message that die() thought it should append.
Thus, fixing it up becomes simple:

$SIG{__DIE__} = sub {
my($message,$append) = @_;
$append = " near line $line of $ARGV." if $append;
die($message.$append);
}

If $message had a terminal \n, then $append would come in empty, and thus
you wouldn't get the message.

> >Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)
>
> andreas

--
Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
Just noticed this in Exporter.pm:

sub export {

# First make import warnings look like they're coming from the "use".
local $SIG{__WARN__} = sub {
my $text = shift;
$text =~ s/ at \S*Exporter.pm line \d+.\n//;
local $Carp::CarpLevel = 1; # ignore package calling us too.
Carp::carp($text);
};
....

Seems like this behaviour is just a general nuisance, really.


--
Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
: My original idea (back when I suggested $SIG{__DIE__}) was that only an
: actual die() would append the " at X line Y." data, and the $SIG{__DIE__}
: routine would never see it. Larry took the opposite tack and it gets
: appended before $SIG{__DIE__} is invoked.

I thought I'd err on the side of not discarding potentially valuable info.
Apparently I did in fact err on that side... :-)

: > Maybe you would prefer that the $SIG{__DIE__} subroutine is called
: > with 3 arguments instead of one?
: >
: > $SIG{__DIE__} = sub {
: > my($message,$file,$line) = @_;
: > }
: >
: > ????
:
: I'd say:
:
: $SIG{__DIE__} = sub {
: my($message,$append) = @_;
: }
:
: where $append is whatever message that die() thought it should append.

I'd call it "$where", but that's neither here nor there.

: Thus, fixing it up becomes simple:
:
: $SIG{__DIE__} = sub {
: my($message,$append) = @_;
: $append = " near line $line of $ARGV." if $append;
: die($message.$append);
: }
:
: If $message had a terminal \n, then $append would come in empty, and thus
: you wouldn't get the message.

Now's the time to change it if we're gonna. Feel free to send a patch.

As long as you're in there, you might think about the relationship of
nested (via local) pseudo-signal handlers. Then again, you might not... :-)

Larry
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
> As long as you're in there, you might think about the relationship of
> nested (via local) pseudo-signal handlers. Then again, you might not... :-)

Ug. diagnostics.pm and CGI::ErrorWrap.pm are both $SIG{__WARN__}
and $SIG{__DIE__} users, and they go to silly steps to try to
make this work. it's something of a hassle.

--tom
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
On Tue, 5 Sep 1995, Tom Christiansen wrote:

> > As long as you're in there, you might think about the relationship of
> > nested (via local) pseudo-signal handlers. Then again, you might not... :-)
>
> Ug. diagnostics.pm and CGI::ErrorWrap.pm are both $SIG{__WARN__}
> and $SIG{__DIE__} users, and they go to silly steps to try to
> make this work. it's something of a hassle.

Mind 'splaining just which bits you don't like? For that matter, care to
explain how $oldwarn in warn_trap could possibly be set to \&warn_trap?

Exactly what behaviour would you prefer.

> --tom

--
Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
On Wed, 6 Sep 1995, Tom Christiansen wrote:

> > Mind 'splaining just which bits you don't like?
>
> i don't like having to keep track of the previous warn/die handler
> when i install a new one in the case that i still want the old
> one to execute.

Well, let's see. Do you want handlers installed before yours to be
executed before or after your handler? What about handlers installed after
yours? Should they have some way of invoking your handler if they want to?

Perhaps we just need to do something like this:

my($oldhandler) = $SIG{__DIE__};
$SIG{__DIE__} = sub {
# do our stuff
if($oldhandler) {
&$oldhandler();
} else {
die; #er, or exit, or however this gets worked out
}
}

Or... perhaps this:

my($oldhandler) = $SIG{__DIE__};
$SIG{__DIE__} = sub {
my($message,$where)=@_;
local($SIG{__DIE__}) = $oldhandler;

# do our stuff

die($message.$where);
}

Or am I going off on the wrong tack?

> > For that matter, care to
> > explain how $oldwarn in warn_trap could possibly be set to \&warn_trap?
>
> repeated imports? redefinition? ok, maybe not. actually, that check
> is in there because i was quite paranoid about (not) ever recursively
> calling myself.

Fair enough. I was thinking the same thing looking through the code.

> --tom

--
Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
On Tue, 5 Sep 1995, Larry Wall wrote:

> I thought I'd err on the side of not discarding potentially valuable info.
> Apparently I did in fact err on that side... :-)

Well, erring on any side is better then not having it at all ;-)

> : where $append is whatever message that die() thought it should append.
>
> I'd call it "$where", but that's neither here nor there.

Fine.

> Now's the time to change it if we're gonna. Feel free to send a patch.

No patch yet. But some ideas: since die() actually takes a list (not that
I've known anyone to use it) how about keeping it in list form for
__DIE__/__WARN__, but appending on the $where message to the argument
list?

That would give us:

$SIG{__DIE__} = sub {
my($where,@msg) = $_[-1], @_[0..-2];

}

> As long as you're in there, you might think about the relationship of
> nested (via local) pseudo-signal handlers. Then again, you might not... :-)

The above change would give us a noticable benefit, in that the signal
handler could change $SIG{__DIE__}, and then reinvoke die() like:

die(@msg,$ourwhere);

or

die(@msg,"");

thus allowing the nested handler to maintain full control over the error
messages.

Of course, I'm not sure what nested dies() do currently. That might have
to be: &$oldhandler(@msg,$ourwhere) and not die().

> Larry

--
Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
> On Tue, 5 Sep 1995, Tom Christiansen wrote:

> > > As long as you're in there, you might think about the relationship of
> > > nested (via local) pseudo-signal handlers. Then again, you might not... :-)
> >
> > Ug. diagnostics.pm and CGI::ErrorWrap.pm are both $SIG{__WARN__}
> > and $SIG{__DIE__} users, and they go to silly steps to try to
> > make this work. it's something of a hassle.

> Mind 'splaining just which bits you don't like?

i don't like having to keep track of the previous warn/die handler
when i install a new one in the case that i still want the old
one to execute.

> For that matter, care to
> explain how $oldwarn in warn_trap could possibly be set to \&warn_trap?

repeated imports? redefinition? ok, maybe not. actually, that check
is in there because i was quite paranoid about (not) ever recursively
calling myself.

--tom
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
> From: Kenneth Albanowski <kjahds@kjahds.com>
>
> On Wed, 6 Sep 1995, Tom Christiansen wrote:
>
> > > Mind 'splaining just which bits you don't like?
> >
> > i don't like having to keep track of the previous warn/die handler
> > when i install a new one in the case that i still want the old
> > one to execute.
>
> Well, let's see. Do you want handlers installed before yours to be
> executed before or after your handler?
> What about handlers installed after yours?

Execute in reverse order. Most recent first.

> Should they have some way of invoking your handler if they want to?
>
Not worth adding anything special for that.

> Perhaps we just need to do something like this:
>
> my($oldhandler) = $SIG{__DIE__};
> $SIG{__DIE__} = sub {
> # do our stuff
> if($oldhandler) {
> &$oldhandler();
> } else {
> die; #er, or exit, or however this gets worked out
> }
> }
>
> Or... perhaps this:
>
> my($oldhandler) = $SIG{__DIE__};
> $SIG{__DIE__} = sub {
> my($message,$where)=@_;
> local($SIG{__DIE__}) = $oldhandler;
> # do our stuff
> die($message.$where);
> }
>
> Or am I going off on the wrong tack?
>
> > > For that matter, care to
> > > explain how $oldwarn in warn_trap could possibly be set to \&warn_trap?
> >
> > repeated imports? redefinition? ok, maybe not. actually, that check
> > is in there because i was quite paranoid about (not) ever recursively
> > calling myself.
>
> Fair enough. I was thinking the same thing looking through the code.
>
I'd like to see something like this:

push @$SIG{__DIE__}, sub {
return 0 unless m/my msg text/; # not one I want to handle
...handle error here...
};

E.g.,
$SIG{__DIE__} is an array of handlers.
Each handler gets called in turn until one returns true.
If $SIG{__DIE__} is not an array ref act as now (compatibility).

Or...
Make local($SIG{__DIE__}) 'magical' so that the previous
handlers get called (in reverse order till one returns true).

Tim.
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
> >
> > Well, let's see. Do you want handlers installed before yours to be
> > executed before or after your handler?
> > What about handlers installed after yours?

> Execute in reverse order. Most recent first.

> > Should they have some way of invoking your handler if they want to?
> >
> Not worth adding anything special for that.

> > Perhaps we just need to do something like this:
> >
> > my($oldhandler) = $SIG{__DIE__};
> > $SIG{__DIE__} = sub {
> > # do our stuff
> > if($oldhandler) {
> > &$oldhandler();
> > } else {
> > die; #er, or exit, or however this gets worked out
> > }
> > }
> >

that's interesting stuff, and it might well be worth doing.

--tom
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
: > > Well, let's see. Do you want handlers installed before yours to be
: > > executed before or after your handler?
: > > What about handlers installed after yours?
:
: > Execute in reverse order. Most recent first.
:
: > > Should they have some way of invoking your handler if they want to?
: > >
: > Not worth adding anything special for that.
:
: > > Perhaps we just need to do something like this:
: > >
: > > my($oldhandler) = $SIG{__DIE__};
: > > $SIG{__DIE__} = sub {
: > > # do our stuff
: > > if($oldhandler) {
: > > &$oldhandler();
: > > } else {
: > > die; #er, or exit, or however this gets worked out
: > > }
: > > }
: > >
:
: that's interesting stuff, and it might well be worth doing.

The code above is, of course, incorrect, since it's passing no argument
(or arguments) to &$oldhandler(). We need to think about this more, and
whether we really want to reinvent the eval {} mechanism poorly.

Larry
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
On Wed, 6 Sep 1995, Larry Wall wrote:

> The code above is, of course, incorrect, since it's passing no argument
> (or arguments) to &$oldhandler(). We need to think about this more, and
> whether we really want to reinvent the eval {} mechanism poorly.

Of course. Code of the top of the head does that sometimes.

I think using a closure is the right action here, as it's cleaner then
$ubstitution, and the __WARN__ handler should be kept dynamic, not
compiled in as a eval {} does. Try this one on for size:

package WarnHandler;

sub new {
my($this,$sub) = @_;
my($oldhandler) = $SIG{__WARN__};

return sub {
my($where,@msg);
if(@_==1) {
# Disect original warning
if ($_[0] =~ /^(.*) (at \S+ line \d+.\n)$/) {
$where=$2;
@msg=($1);
} else {
@msg=$_[0];
$where="";
}
} else {
# Pass along previously disected warning
$where = shift @_;
@msg = @_;
}
#print "w=$where, m=",join("|",@msg),"\n";
{
# Make sure we can't recurse
local($SIG{__WARN__})="";
my(@ret)=&$sub($where,@msg);
($where,@msg)=@ret;
} continue {
#print "w=$where, m=",join("+",@msg),"\n";
if( $oldhandler ) {
&$oldhandler($where,@msg);
} else {
warn(@msg,($where?" ":""),$where);
}
}
};
}

package main;


local($SIG{__WARN__}) = new WarnHandler sub { print join("|","",@_,""),"\n"; next };

local($SIG{__WARN__}) = new WarnHandler sub {
my($where,@msg)=@_;
print "Dear, dear, dear. ",join("",@msg)," $where\n";
warn "test warning";
next;
};

local($SIG{__WARN__}) = new WarnHandler sub {
my($where,@msg)=@_;
chop $where;
return "({$where})\n",@msg;
};


warn "Invalid something or other";

__END__


This one has some interesting capabilities. It fixes up the $where
problem, by brute force, and it lets warn handlers have full control over
the future: you be the C<last> handler or go to the C<next> one, or
C<return> a set of parameters to be used by other handlers. I think this
takes care of all the important stuff.

> Larry

--
Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
[Proposal for generating warning handlers elided]

> return sub {
> my($where,@msg);

I'm a bit slow catching up on this thread, but before we get too far along, I'd
like to put in a word of support for Larry Wall's notion that warning handlers
return $file,$line for the current warning as separate items. That'd make it
easier to manipulate the offending source code in a complex handler, and the
default behavior would just involve creating the string "at $file line $line".

I realize that that under Kenneth Albanowski's scheme, getting at the location
of the error is just a matter of a pattern match, but it seems cleaner to
construct the string only when one needs it. Either option will require
shifting the location information up from mess() to warn(), croak(), or die();
it's just a matter of one string vs. a string and a number.

Regards,
Charles Bailey bailey@genetics.upenn.edu
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
Whoops, mail to p5p failed. Here's a repost:

package WarnHandler;

sub new {
my($this,$sub) = @_;
my($oldhandler) = $SIG{__WARN__};

return sub {
my($file,$line,@msg);
if(@_==1) {
# Disect original warning
if ($_[0] =~ /^(.*) at (\S+) line (\d+).\n$/) {
$file=$2;
$line=$3;
@msg=($1);
} else {
@msg=$_[0];
$file="";
$line="";
}
} else {
# Pass along previously disected warning
$file = shift @_;
$line = shift @_;
@msg = @_;
}
{
# Make sure we can't recurse
local($SIG{__WARN__})="";
my(@ret)=&$sub($file,$line,@msg);
($file,$line,@msg)=@ret;
} continue {
if( $oldhandler ) {
&$oldhandler($file,$line,@msg);
} else {
warn(@msg,($file?" at $file line $line.":""));
}
}
};
}

package main;


local($SIG{__WARN__}) = new WarnHandler sub { print join("|","",@_,""),"\n"; next };

local($SIG{__WARN__}) = new WarnHandler sub {
my($file,$line,@msg)=@_;
print "Dear, dear, dear. ",join("",@msg),"\n";

warn "test warning"; # trigger unhandled warning

next;
};

local($SIG{__WARN__}) = new WarnHandler sub {
my($file,$line,@msg)=@_;
#demo a handler that just changes the data
return "","",@msg," at line $line of $file\n";
};


warn "Invalid something or other";


--
Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
: [Proposal for generating warning handlers elided]
:
: > return sub {
: > my($where,@msg);
:
: I'm a bit slow catching up on this thread, but before we get too far along, I'd
: like to put in a word of support for Larry Wall's notion that warning handlers
: return $file,$line for the current warning as separate items. That'd make it
: easier to manipulate the offending source code in a complex handler, and the
: default behavior would just involve creating the string "at $file line $line".
:
: I realize that that under Kenneth Albanowski's scheme, getting at the location
: of the error is just a matter of a pattern match, but it seems cleaner to
: construct the string only when one needs it. Either option will require
: shifting the location information up from mess() to warn(), croak(), or die();
: it's just a matter of one string vs. a string and a number.

Uh, the attributions are getting fouled up here. Andreas Koenig
originally proposed the 3 arg form, I believe. And Kenneth doesn't
*want* to do pattern matching--that's what brought this all on in the
first place... :-)

On the other hand, I don't see how you can get out of pattern matching if
the user said something like

die "oops at $0 line " . (__LINE__ + $evalbase) . "\n";

Larry
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
On Thu, 7 Sep 1995, Larry Wall wrote:

> Uh, the attributions are getting fouled up here. Andreas Koenig
> originally proposed the 3 arg form, I believe. And Kenneth doesn't
> *want* to do pattern matching--that's what brought this all on in the
> first place... :-)
>
> On the other hand, I don't see how you can get out of pattern matching if
> the user said something like
>
> die "oops at $0 line " . (__LINE__ + $evalbase) . "\n";

Agreed. I actually don't mind the pattern matching in the WarnHandler
style handler, since it takes care of separating out the parts for you.

> Larry

--
Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
Larry Wall wrote:
> Charles Bailey wrote:
> : I'm a bit slow catching up on this thread, but before we get too far along, I'd
> : like to put in a word of support for Larry Wall's notion that warning handlers
> : return $file,$line for the current warning as separate items. That'd make it
> : easier to manipulate the offending source code in a complex handler, and the
> : default behavior would just involve creating the string "at $file line $line".
> :
> : I realize that that under Kenneth Albanowski's scheme, getting at the location
> : of the error is just a matter of a pattern match, but it seems cleaner to
> : construct the string only when one needs it. Either option will require
> : shifting the location information up from mess() to warn(), croak(), or die();
> : it's just a matter of one string vs. a string and a number.
>
> Uh, the attributions are getting fouled up here. Andreas Koenig
> originally proposed the 3 arg form, I believe. And Kenneth doesn't
> *want* to do pattern matching--that's what brought this all on in the
> first place... :-)

Wups. I apologize for tangling the thread.

> On the other hand, I don't see how you can get out of pattern matching if
> the user said something like
>
> die "oops at $0 line " . (__LINE__ + $evalbase) . "\n";

As far as I can see, you can't. I think I'm being unclear about what I'm
suggesting. Let me try again: Ideally, when an exception is thrown, I'd like
to see three data associated with it:
$file - path to the file in which the code that threw the exception was
found. In the case of an eval, this might be one of
o while ($eval_depth) {
$file .= "eval (line $eval_line[$eval_depth--]): ";
}
$file .= " some/where/Over/Rainbow.pm";
This allows one to recognize that the error occurrent in
an eval, but to anchor it in a file somewhere, and to
pull out the file name with a /: (\S+)$/. It'd require
the most internal modifications, of course.
o "some/where/Over/Rainbow.pm"
Gets one directly to the nearest "permanent" point of
reference, but loses information about eval context.
It'd probably require only slightly less in the way of
internal modifications than the previous option.
o "(eval $n)"
Simple, but of minimal utility in tracking down some
persistent reference point for debugging. Requires
no internal modification, beyond pushing the filegv
directly onto the stack instead of wrapping it in
the "at %s line %d" form.
$line - line in $file executing when the exception was thrown. This is
again a problem when the exception occurs inside an eval, but,
expecially in combination with the first option above, I'd be
inclined to make this the line of the "innermost" actual file
(including -e) executing.
$msg - whatever the user passed as an argument to C<warn> or C<die>.

Basically, I'm trying to set out a mechanism by which a handler receives
"reliable" information about the location of an exception, without having
to depend on the way that the user formats the message passed to C<die> or
C<warn>. I see this as an advantage for a few reasons:
o It may make things simpler for handlers with an interest in the
location of the exceptions.
o It provides a uniform way to locate the spot at which the exception
occurred, without requiring everyone who throws an exception to adhere
to a particular convention when formatting message. Of course, handlers
which are aware that $msg is going to come to them in a particular format
are welcome to take advantage of that fact.
o It shifts the process of constructing the "at %s line %d" suffix out to
the default or "last-chance" exception handler, which means that
exceptions which get passed down a line of handlers won't cause a lot
of building and tearing down of strings.

I realize that the details get a bit fuzzy when dealing with nested evals, but
I don't know of any way, absent passing around a stack of "interpreter frames",
to adequately represent the location of an exception buried deep among the
evals.

Well, that's my $0.02, perhaps with a little interest. I hope it's a bit
clearer than my first try.

Regards,
Charles Bailey bailey@genetics.upenn.edu
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
Charles Bailey writes:
> I realize that the details get a bit fuzzy when dealing with nested evals, but
> I don't know of any way, absent passing around a stack of "interpreter frames",
> to adequately represent the location of an exception buried deep among the
> evals.
>

I do not think that nested evals are of any problem, since at least
this info is recoverable now.

As always on this list, I repeat the same again: the most complicated
problem is subs defined inside eval. I think that something like

use debug -g;

that will preserve the text of eval inside the CV is needed here.

Ilya
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
On Fri, 8 Sep 1995, Charles Bailey wrote:

> Well, that's my $0.02, perhaps with a little interest. I hope it's a bit
> clearer than my first try.

Thanks, this is some excellent material. First of all, how do you feel
about _not_ changing Perl itself, and using a pre-handler that massages
(or actually creates) the trace data in the format that you want? That
seems to be relatively easy to do using a syntax like:

local($SIG{__DIE__}) = new DieHandler sub {
my($file,$line,@msg) = @_;
#...
last #handler
};

If this seems reasonable, then the steps that the DieHandler takes seem
fairly simple:

1. trace the caller tree, using something roughly like:

$i=0;
while (@a= caller($i++)) {
print "\n",join("|",@a),"\n";
$sub = $a[3];
$line = $a[2];
$file = $a[1];
if( $file =~ /^\(eval/ ) {
$oline = (caller($i))[2];
print "the eval at line $oline of ";
} else {
print $file,"\n";
last;
}
}

This gives the full location, in any format you'd like, within what
caller() can provide. (Which, as Ilya has mentioned, is everything but
the contents of subs defined in evals. Also, in a quick test, anonymous
subs may need a bit more work to catch properly.)

Note that in this format, the messages is reversed into "line $l of $f" to
get it to form decent English. Nothing major there.


2. Take what die() provides to a __DIE__ handler, and "digest" it.
Specifically, if it ends in " at \S+ line \d+.\n", then just chop it off,
and make sure there is no newline at the end.


3. Return an closure that calls the provided sub/closure with three
arguments: $file (the trace above), $line (the innermost line number),
and @msg (or $msg, if you prefer) which is what the __DIE__ handler gets.

Something similar to this seems to work fine:

sub NewDieHandler {
my($sub) = @_;
my($oldhandler)=$SIG{__DIE__};
return sub {
my($file,$line,$msg);
if(@_==1) { #__DIE__ call
#digest & trace
} else {
($file,$line,$msg)=@_;
}
{
&$sub();
} continue {
&$oldhandler($file,$line,$msg) if $oldhandler;
}

}
}


4. Install a default handler as part of this mechanism consisting of:

sub {
my($file,$line,$msg) = @_;
if( substr($msg,-1,1) eq "\n" ) {
die $msg;
} else {
die "$msg at line $line of $file.\n";
}
}


Note that a more robust WarnHandler could let the sub (by returning
different values) change the $file, $line and/or $msg that the next
handler in the chain sees.

So (after all that), does this look like it will do all that you are
looking for?

> Regards,
> Charles Bailey bailey@genetics.upenn.edu


--
Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
Kenneth Albanowski wrote:
>On Fri, 8 Sep 1995, Charles Bailey wrote:
>
>> Well, that's my $0.02, perhaps with a little interest. I hope it's a bit
>> clearer than my first try.
>
>Thanks, this is some excellent material. First of all, how do you feel
>about _not_ changing Perl itself, and using a pre-handler that massages
>(or actually creates) the trace data in the format that you want? That

Sounds fine -- the only reason I suggested changing the way Perl sets up the
error messages is to improve efficiency. Coding the initial pass in Perl
shouldn't be a problem; if exception-driven code in the future needs better
performance, we can address the issue then.


> 1. trace the caller tree, using something roughly like:
>
> $i=0;
> while (@a= caller($i++)) {
> print "\n",join("|",@a),"\n";
> $sub = $a[3];
> $line = $a[2];
> $file = $a[1];
> if( $file =~ /^\(eval/ ) {
> $oline = (caller($i))[2];
> print "the eval at line $oline of ";
> } else {
> print $file,"\n";
> last;
> }
> }
>
>This gives the full location, in any format you'd like, within what
>caller() can provide. (Which, as Ilya has mentioned, is everything but
>the contents of subs defined in evals. Also, in a quick test, anonymous
>subs may need a bit more work to catch properly.)
>
> [text deleted]
>
> 3. Return an closure that calls the provided sub/closure with three
>arguments: $file (the trace above), $line (the innermost line number),
>and @msg (or $msg, if you prefer) which is what the __DIE__ handler gets.

Sounds OK. I've no preference between $msg and @msg. IWBNI if the format of
$file made it easy to pick out the spec for the file in which $line is located.
Perhaps it could be quoted somehow, or, in the format you use above, /(\S+)\n/
should do the trick.

>Something similar to this seems to work fine:
>
> sub NewDieHandler {
> my($sub) = @_;
> my($oldhandler)=$SIG{__DIE__};
> return sub {
> my($file,$line,$msg);
> if(@_==1) { #__DIE__ call
> #digest & trace
> } else {
> ($file,$line,$msg)=@_;
> }
> {
> &$sub();
> } continue {
> &$oldhandler($file,$line,$msg) if $oldhandler;
> }
>
> }
> }

Sounds fine, if the local($SIG{__DIE__}) is used to handle scoping. We're
still left with ways to deal with concurrent exceptions (e.g. what effect do we
want if &$sub generates an exception?). For now, it may be best to wrap &$sub
and &$oldhandler in an eval, to insure that any exceptions it generates aren't
passed to $SIG{__DIE__}, and around and around . . .

> 4. Install a default handler as part of this mechanism consisting of:
>
> sub {
> my($file,$line,$msg) = @_;
> if( substr($msg,-1,1) eq "\n" ) {
> die $msg;
> } else {
> die "$msg at line $line of $file.\n";
> }
> }

Again, the C<die> in the sub can't call $SIG{__DIE__}, or it'll loop. Do we
have to say
print STDERR $msg;
exit $!; # or some analog which mimics current behavior
explicitly?

>Note that a more robust WarnHandler could let the sub (by returning
>different values) change the $file, $line and/or $msg that the next
>handler in the chain sees.
>
>So (after all that), does this look like it will do all that you are
>looking for?

Seems like a good first cut. I'm sure I'm missing something that I'll realize
only when it comes up in a concrete example, but then, that's what v1.0 is for.

Thanks.

Regards,
Charles Bailey bailey@genetics.upenn.edu
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
: Again, the C<die> in the sub can't call $SIG{__DIE__}, or it'll loop. Do we
: have to say
: print STDERR $msg;
: exit $!; # or some analog which mimics current behavior
: explicitly?

No, the __DIE__ handler is explicitly disabled during the call, so that you
can die from a __DIE__ handler. Similarly for __WARN__.

Larry
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
Larry Wall wrote:
> : Again, the C<die> in the sub can't call $SIG{__DIE__}, or it'll loop. Do we
> : have to say
> : print STDERR $msg;
> : exit $!; # or some analog which mimics current behavior
> : explicitly?
>
> No, the __DIE__ handler is explicitly disabled during the call, so that you
> can die from a __DIE__ handler. Similarly for __WARN__.

Um, right. I should've checked util.c. This means that a handler can't itself
signal an exception; I'm not sure this is a good thing. "Resignaling" the
current exception is just a matter of adopting as a convention the rule that if
a handler returns TRUE, execution should resume normally, while if it returns
FALSE, the next handler out should be called. We're sorta stuck, however, if a
handler needs to create a new exception. For instance, consider something like
this:
1. A routine in package Foo::Bar fails to complete a task, so signals
an exception, which is caught by a handler set up in package Foo::Bar.
2. The handler tries a fall-back approach to the problem, and fails
as well.
At this point, it would be ideal for the handler to signal an exception that
indicates that it has failed as well, so that handlers in Foo and main and
wherever get a chance to respond. In order for this to work, either
Foo::Bar::die_handler must be able to signal an exception itself, or it must be
able to modify the "exception record" passed to it. I think the former option
would be better, as the latter would involve replicating the common code
proposed for DieHandler::new in each handler that might want to resignal.

I guess the model which seems most natural to me is that an exception can be
signalled at any time, and it is passed to from handler to handler, working
from the innermost enclosing scope out, until a handler dismisses the
exception, or the program terminates. For purposes of this chain, a handler is
considered to live just "outside" the scope in which it was established, so
that if it signals an exception itself, and it hasn't explicitly established a
handler, the first handler to see an exception is that for the scope just
"outside" the scope in which that handler was established. For instance, of a
handler established at stack depth 5 signals an exception, the handlers
established at depth 5,4,3,2,1,0,last-chance are given a shot at the exception,
in that order. If the handler at depth 3 signals an exception itself, then
that's handed off immediately to handlers at depth 2,1,0,last-chance. If this
new exception is dismissed, then processing of the original exception resumes
where it was interrupted.

I'm sure my VMS background is showing here, but I've found this approach to be
quite useful.

Regards,
Charles Bailey bailey@genetics.upenn.edu
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
On Mon, 11 Sep 1995, Charles Bailey wrote:

> Sounds fine -- the only reason I suggested changing the way Perl sets up the
> error messages is to improve efficiency. Coding the initial pass in Perl
> shouldn't be a problem; if exception-driven code in the future needs better
> performance, we can address the issue then.

Hmmm. Didn't think about exceptions... Well, I don't think they'll be an
issue. Beside, if someone is exception happy, it might behoove them to
add a handler like:

$SIG{__DIE__} = new DieHandler sub {
my($file,$line,$msg);
if($msg =~ /^Exception: /) {
die $msg;
}
next;
};

which cuts short any previous handlers. (Hmmm. Maybe this actually should
go into a _pre_handler chain, which can get control before the normal
handlers. Something to think about here.)

> Sounds OK. I've no preference between $msg and @msg. IWBNI if the format of
> $file made it easy to pick out the spec for the file in which $line is located.
> Perhaps it could be quoted somehow, or, in the format you use above, /(\S+)\n/
> should do the trick.

Perhaps this?

my($file,$evalscope,$line,$msg)=@_;
print "$msg at line $line of $evalscope$file\n";

Whatever gets done won't please someone, so it probably doesn't matter
enourmously.

> Sounds fine, if the local($SIG{__DIE__}) is used to handle scoping. We're
> still left with ways to deal with concurrent exceptions (e.g. what effect do we
> want if &$sub generates an exception?). For now, it may be best to wrap &$sub
> and &$oldhandler in an eval, to insure that any exceptions it generates aren't
> passed to $SIG{__DIE__}, and around and around . . .

As Larry has mentioned, $SIG{__DIE__} disables any die-handling
(regardless of assignments to $SIG{__DIE__}) within the handler.

> Again, the C<die> in the sub can't call $SIG{__DIE__}, or it'll loop. Do we
> have to say
> print STDERR $msg;
> exit $!; # or some analog which mimics current behavior
> explicitly?

We need to use die(), otherwise exception handling won't work. (Thanks
for reminding me about exceptions ;-)

> Seems like a good first cut. I'm sure I'm missing something that I'll realize
> only when it comes up in a concrete example, but then, that's what v1.0 is for.

Exactly. I'll work out a full module and post it.

BTW, do you think this should be a separate module, or part of Carp?

> Thanks.
>
> Regards,
> Charles Bailey bailey@genetics.upenn.edu
>

--
Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
On Mon, 11 Sep 1995 09:57:28 PDT, Larry Wall wrote:
>: Again, the C<die> in the sub can't call $SIG{__DIE__}, or it'll loop. Do we
>: have to say
>: print STDERR $msg;
>: exit $!; # or some analog which mimics current behavior
>: explicitly?
>
>No, the __DIE__ handler is explicitly disabled during the call, so that you
>can die from a __DIE__ handler. Similarly for __WARN__.
>
>Larry
>

The same ought to be true for DESTROY also, but it isn't. Try this devious
little infinite looper for kicks:

package Foo;
sub new { bless {} }
sub DESTROY { my($s) = Foo->new(); print "." }
package main;
Foo->new();
__END__
......<forever>

We probably ought to check CvDEPTH in sv_clear() as well.


- Sarathy.
gsar@engin.umich.edu
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
On Mon, 11 Sep 1995, Charles Bailey wrote:

> Um, right. I should've checked util.c. This means that a handler can't itself
> signal an exception; I'm not sure this is a good thing. "Resignaling" the
> current exception is just a matter of adopting as a convention the rule that if
> a handler returns TRUE, execution should resume normally, while if it returns
> FALSE, the next handler out should be called. We're sorta stuck, however, if a
> handler needs to create a new exception. For instance, consider something like
> this:
> 1. A routine in package Foo::Bar fails to complete a task, so signals
> an exception, which is caught by a handler set up in package Foo::Bar.
> 2. The handler tries a fall-back approach to the problem, and fails
> as well.
> At this point, it would be ideal for the handler to signal an exception that
> indicates that it has failed as well, so that handlers in Foo and main and
> wherever get a chance to respond. In order for this to work, either
> Foo::Bar::die_handler must be able to signal an exception itself, or it must be
> able to modify the "exception record" passed to it. I think the former option
> would be better, as the latter would involve replicating the common code
> proposed for DieHandler::new in each handler that might want to resignal.

In the DieHandler model that I've been using, if a handler says "next" in
it's outermost scope, then the next handler in the chain executes, using
the same error message that this handler got. If it says "last", then the
handler chain is canceled, and control returns to the routine that called
die(). If "return" is used (or falling of the end of the handler) then
the returned array is used as the data to pass to any further handlers.

Is this sufficient?

> I guess the model which seems most natural to me is that an exception can be
> signalled at any time, and it is passed to from handler to handler, working
> from the innermost enclosing scope out, until a handler dismisses the
> exception, or the program terminates. For purposes of this chain, a handler is
> considered to live just "outside" the scope in which it was established, so
> that if it signals an exception itself, and it hasn't explicitly established a
> handler, the first handler to see an exception is that for the scope just
> "outside" the scope in which that handler was established. For instance, of a
> handler established at stack depth 5 signals an exception, the handlers
> established at depth 5,4,3,2,1,0,last-chance are given a shot at the exception,
> in that order. If the handler at depth 3 signals an exception itself, then
> that's handed off immediately to handlers at depth 2,1,0,last-chance. If this
> new exception is dismissed, then processing of the original exception resumes
> where it was interrupted.

Hmm. The last bit wouldn't happen right now. The exception chain can be
traced down, but it cannot be invoked in the middle to start a parellel
trace. I'll have to think about exceptions a bit more, and see how this
plays into it. (I probably could set something up like that by have the
DieHandler execute the real handler inside an eval block to capture
actual dies, and patch that through...)

I think we need a standardized exception mechanism, by the way, and this
seems to be a perfect place to put it in.

> I'm sure my VMS background is showing here, but I've found this approach to be
> quite useful.
>
> Regards,
> Charles Bailey bailey@genetics.upenn.edu
>

--
Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
While I'm thinking about exceptions, does anyone have an comments on
which of the following are preferable? (I know these aren't complete
and/or workable. These are just off-the-cuff examples of technique.)

1. The OO approach

package Exception;

sub throw {
@main::_tuckexception=@_;
die "EXCEPTION\n";
};

#$SIG{__DIE__} and catch left as an exercise for the reader

package FileException;

@ISA = ("Exception");

package FileOpenException;

@ISA = ("FileException");

package main;


open FILE, "<foo" or throw FileOpenException "foo";


2. The frozen text approach

sub throw {
die "EXCEPTION: ",freezearray(@_);
}

$SIG{__DIE__} = sub {
if($_[0] =~ /^EXCEPTION: /) {
@exception = thawarray($');
# base further execution on $execution[0], or
# something like that
} else {
die(@_);
}
};

open FILE, "<foo" or throw "fileopen","foo";


3. The array approach

sub throw {
@mail::_tuckexception = @_;
die "EXCEPTION\n";
}

...

The key thing seems to be with the OO style, you get a rigourous
inheritance relationship, while with text, you need to do "fileopen" =~
/^file/ matching, or something equally prone to error.

--
Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
On Tue, 12 Sep 1995, Dale Amon wrote:

> Basically there are several cases a handler needs to deal with
>
> 1) The error is something that this handler can fix. It does
> so and returns control to the site of the error.

Resumption.

> 2) The error is not repairable, but survivable. The handler
> cleans up loose ends and returns control to the context
> in which the exception was caught.

Resumption again, but this one is a bit iffy. I think OS's need this more
then applications do. GC would come under this or the previous one.

> 3) The error is not repairable at this level. The handler
> punts the error to the next enclosing error context. It
> should have the option of changing the text, codes, etc
> that are passed upwards.

Rethrow.

> 4) The error is recognized at the level as absolutely fatal.
> The handler causes the program to exit and possibly dump
> immediately.

Die.

> As Charles noted, you always have a default level 0 error handling
>
> context that is of type 4. It catches exceptions if one raises
> exceptions outside of a handler context or does not have an such
> contexts at all; or if the users top level context is of type 3 and
> tries to pass the exception on up.
>
> Just a few cents worth from an old OS hacker...

In playing with exception handling in relation to die(), I'm a little
surprised to say that I don't think die() is needed for much at all, now
that we have closures. If you set the handlers for exceptions up as
closures instead of code at an outer scope, then you can do all sorts of
neat stuff, including resumption.

Given this, I think I'll just ignore exceptions for now, and finish up my
DieHandler module, and see how it flies.

--
Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
: Given this, I think I'll just ignore exceptions for now, and finish up my
: DieHandler module, and see how it flies.

In other words, if setting up the closures on scope entry imposes too
much overhead, the DieHandler will die a (hopefully) natural death.
Mmm. I have a sneakin' suspicion that eval {} is going to be
significantly faster for non-exceptional code, especially if the
closures in question access any external lexical variables. Though
the constructor overhead will certainly dominate.

Larry
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
On Tue, 12 Sep 1995, Larry Wall wrote:

> : Given this, I think I'll just ignore exceptions for now, and finish up my
> : DieHandler module, and see how it flies.
>
> In other words, if setting up the closures on scope entry imposes too
> much overhead, the DieHandler will die a (hopefully) natural death.

Just about, yes.

> Mmm. I have a sneakin' suspicion that eval {} is going to be
> significantly faster for non-exceptional code, especially if the
> closures in question access any external lexical variables. Though
> the constructor overhead will certainly dominate.

Well, the constructor has virtually _no_ overhead, other then setting up
the closure, and that will dominate. I should run some tests to see how
the speed stack up against eval {}.

> Larry

--
Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
Although I'm not working on Perl source, I've written many an

exception handling system...

Basically there are several cases a handler needs to deal with

1) The error is something that this handler can fix. It does
so and returns control to the site of the error.

2) The error is not repairable, but survivable. The handler
cleans up loose ends and returns control to the context
in which the exception was caught.

3) The error is not repairable at this level. The handler
punts the error to the next enclosing error context. It
should have the option of changing the text, codes, etc
that are passed upwards.

4) The error is recognized at the level as absolutely fatal.
The handler causes the program to exit and possibly dump
immediately.

As Charles noted, you always have a default level 0 error handling

context that is of type 4. It catches exceptions if one raises
exceptions outside of a handler context or does not have an such
contexts at all; or if the users top level context is of type 3 and
tries to pass the exception on up.

Just a few cents worth from an old OS hacker...

Dale Amon
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
On Tue, 12 Sep 1995, Larry Wall wrote:

> : Given this, I think I'll just ignore exceptions for now, and finish up my
> : DieHandler module, and see how it flies.
>
> In other words, if setting up the closures on scope entry imposes too
> much overhead, the DieHandler will die a (hopefully) natural death.
> Mmm. I have a sneakin' suspicion that eval {} is going to be
> significantly faster for non-exceptional code, especially if the
> closures in question access any external lexical variables. Though
> the constructor overhead will certainly dominate.

Here's the result of a quick trial, using semi-functional code (these
tests probably don't represent actually useful code). I must admit that
some of these are a bit surprising.

0.000722 sec/new closure via constructor
0.000445 sec/new anonymous sub via constructor
0.000038 sec/assignment of anonymous sub to $SIG{__DIE__}
0.000029 sec/assignment of "" to $SIG{__DIE__}
0.000039 sec/eval {} without any mention of $SIG{__DIE__} or subs
0.000617 sec/new closure via subroutine
0.000176 sec/new closure without any calls to subs or methods
0.000199 sec/no-op call to a sub
0.000218 sec/no-op call to a method

All in all, making a closure is definitely more expensive then an
anonymous sub, but not to a degree that it hinders use of it. Just doing
a call to a subroutine or method swamps things down.


In summary, this:

$SIG{__DIE__} = new DieHandler sub {
#whatever, but this isn't a closure, just an anon sub
};

appears to be about four times as expensive as

$SIG{__DIE__} = sub {
#whatever, but this is a closure, not an anon sub
};

or it does in this round of tests. A difference, yes. A difference worthy
of discarding DieHandler: no, I think not.

This is a good point for using eval {} over DieHandlers at all, though, at
least if you are repeated bouncing between scopes that have their own
handler. I doubt it would matter to a Tk dialog error handler.

For a hypothetical exception handler that executes exceptions as closures
_within_ the scope of the failed code (to faciliate resumption) and only
die() if there no exception handler can cope -- I have absolutely no idea
how efficient it would be, and whether it would be affected by these
stats.

> Larry

--
Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
> From: Kenneth Albanowski <kjahds@kjahds.com>
>
> On Tue, 12 Sep 1995, Larry Wall wrote:
>
> > : Given this, I think I'll just ignore exceptions for now, and finish up my
> > : DieHandler module, and see how it flies.
> >
> > In other words, if setting up the closures on scope entry imposes too
> > much overhead, the DieHandler will die a (hopefully) natural death.
> > Mmm. I have a sneakin' suspicion that eval {} is going to be
> > significantly faster for non-exceptional code, especially if the
> > closures in question access any external lexical variables. Though
> > the constructor overhead will certainly dominate.

> In summary, this:
>
> $SIG{__DIE__} = new DieHandler sub {
> #whatever, but this isn't a closure, just an anon sub
> };
>
> appears to be about four times as expensive as
>
> $SIG{__DIE__} = sub {
> #whatever, but this is a closure, not an anon sub
> };
>
> or it does in this round of tests. A difference, yes. A difference worthy
> of discarding DieHandler: no, I think not.
>
Forgive me but I've not been following this very closely (no time).

I've always viewed $SIG{__DIE__} as a debugging intervention tool and
not something you could build an exception handling mechanism out of.

Could someone recap in very simple terms what problem is being solved here?

What advantages are being offered over the current 'standard' approach of:

eval {

};
if ($@) {

... handle error in $@ else die ...
}

Tim.
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
On Wed, 13 Sep 1995, Tim Bunce wrote:

> Forgive me but I've not been following this very closely (no time).
>
> I've always viewed $SIG{__DIE__} as a debugging intervention tool and
> not something you could build an exception handling mechanism out of.

Quite right. But $SIG{__DIE__} incidentally gets control of an
"exception" before the exception handler will, so it's something to think
about.

> Could someone recap in very simple terms what problem is being solved here?
>
> What advantages are being offered over the current 'standard' approach of:
>
> eval {
>
> };
> if ($@) {
>
> ... handle error in $@ else die ...
> }

Using $SIG{__DIE__}? None. Indeed, if you have some sort of global
handler, it actually makes it more complex. But there is no direct
usefulness in trapping exceptions.

The point is that if I have:

$SIG{__DIE__} = new DieHandler sub {
if(tk_error(@_) eq "Resume") { last } else { next}
};

Then to do exceptions you might also need to say:

local($SIG{__DIE__}) = new DieHandler sub {
die(@_) if $_[0] =~ /^Exception/;
};

Or whatever message you are trying to trap -- pass it along so it can pop
out of the eval, in other words.

Of course, if your:

if ($@) {
... handle error in $@ else die ...
}

is very concientious about die'ing if it doesn't know how to handle the
error, then a standard DieHandler might be able to get away with _not_
triggering massive changes in the error flow if it's inside an eval...

> Tim.
>

--
Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
Kenneth Albanowski wrote:
| On Wed, 13 Sep 1995, Tim Bunce wrote:
|
| > Forgive me but I've not been following this very closely (no time).
| >
| > I've always viewed $SIG{__DIE__} as a debugging intervention tool and
| > not something you could build an exception handling mechanism out of.
|
| Quite right. But $SIG{__DIE__} incidentally gets control of an
| "exception" before the exception handler will, so it's something to think
| about.

Hmm. From what I can see, $SIG{__DIE__} is the only thing out of which one
could build an exception handler. Perhaps the difference in view lies in the
definition of exception. I thinking of exceptions as events which interrupt
the normal flow of execution because the programmer felt a condition required
immediate action. This is distinct from errors which are reported back to the
caller, with or without terminating the execution of the current routine.

| > Could someone recap in very simple terms what problem is being solved here?
| >
| > What advantages are being offered over the current 'standard' approach of:
| >
| > eval {
| >
| > };
| > if ($@) {
| >
| > ... handle error in $@ else die ...
| > }
|
| Using $SIG{__DIE__}? None. Indeed, if you have some sort of global
| handler, it actually makes it more complex. But there is no direct
| usefulness in trapping exceptions.

Apart from conceptual differences, there is one class of problem which can't be
handled by the C<eval { ... } if ($@) { ... }> approach: recoverable errors.
By the time one checks $@, execution has moved past the point of error, the
scope in which the exception was generated has been exited, lexicals have been
destroyed, etc. Building the exception handling around pseudo-signal-handlers
like $SIG{__DIE__} could allow one to react to the exception as soon as it
occurs, and then resume normal execution if the error is recoverable.

From the perspective of handlers that report the error, clean up, and get out,
I don't see much conceptual difference. There may be a small advantage in
efficiency using $SIG{__DIE__}, since one doesn't have to construct (possible
several nested) eval scope(s) when executing code which one expects will
not generate exceptions in the normal case.

Regards,
Charles Bailey bailey@genetics.upenn.edu
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
On Wed, 13 Sep 1995, Charles Bailey wrote:

> Hmm. From what I can see, $SIG{__DIE__} is the only thing out of which one
> could build an exception handler. Perhaps the difference in view lies in the
> definition of exception. I thinking of exceptions as events which interrupt
> the normal flow of execution because the programmer felt a condition required
> immediate action. This is distinct from errors which are reported back to the
> caller, with or without terminating the execution of the current routine.

No, $SIG{__DIE__} isn't the only way to build an exception handler, as
you'll see below.

> Apart from conceptual differences, there is one class of problem which can't be
> handled by the C<eval { ... } if ($@) { ... }> approach: recoverable errors.
> By the time one checks $@, execution has moved past the point of error, the
> scope in which the exception was generated has been exited, lexicals have been
> destroyed, etc. Building the exception handling around pseudo-signal-handlers
> like $SIG{__DIE__} could allow one to react to the exception as soon as it
> occurs, and then resume normal execution if the error is recoverable.

Yes, $SIG{__DIE__} can be used for that, but you can also use other
techniques.

> From the perspective of handlers that report the error, clean up, and get out,
> I don't see much conceptual difference. There may be a small advantage in
> efficiency using $SIG{__DIE__}, since one doesn't have to construct (possible
> several nested) eval scope(s) when executing code which one expects will
> not generate exceptions in the normal case.

It's hard to say.

Here's the basic plan for an exception system that is mostly clear of
$SIG{__DIE__}:

catch sub {
# Code to execute that may throw an exception
}, FileOpenException => sub {
# execute this code on a FileOpen exception
}, finally => sub {
# execute this code after leaving the code scope, no matter what.
};

Throw looks like this:

throw FileOpenException; #optional, @moredata;

Inside each of the catch handlers, you can use:

rethrow #optional exception, @moredata;


I don't have the internals of catch and throw worked out yet, but the
basic idea is this: keep a stack of exception actions (with each action
being a closure), and on an exception (when throw() is invoked)
_directly_ call the closure that handles that exception, if one exists.
If no handler is found, the "finally" closure gets executed, and then the
exception stack is peeled back by one to look for handlers in the next
scope. Note that _all_ of this is happening within the throw() call, and
the real stack scope never changes, we are relying on the closures to figure
out where they belong. It's only after a handler finishes that we figure
out how far back in the stack we need to be, and _then_ use die() to peel
back the perl stack.

I'm not even sure that final die() is needed, though, as it may be
possible to do this with a global variable and a return. I'm a little
fuzzy on the exact implementation details, but it seems feasible.
(Whether it would be efficient is unknown.)

I must say that, all things considered, closures in perl are a great deal
of fun. :-)

> Regards,
> Charles Bailey bailey@genetics.upenn.edu

--
Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
Kenneth Albanowski wrote:
| On Wed, 13 Sep 1995, Charles Bailey wrote:
|
| > Hmm. From what I can see, $SIG{__DIE__} is the only thing out of which one
| > could build an exception handler. Perhaps the difference in view lies in the
| > definition of exception. I thinking of exceptions as events which interrupt
| > the normal flow of execution because the programmer felt a condition required
| > immediate action. This is distinct from errors which are reported back to the
| > caller, with or without terminating the execution of the current routine.
|
| No, $SIG{__DIE__} isn't the only way to build an exception handler, as
| you'll see below.

Ah. Sorry; I was imprecise in my original statement. As far as I can see,
$SIG{__DIE__} is the only mechanism extant in Perl from which one could build
an exception handling mechenism. Perl would have to be modified to allow
execution to resume if a handler returned an "OK" status, and we'd need to sort
out actions for "nested" exception chains, but the basic principle is there.

If one is willing to build an exception handling mechanism into Perl de novo,
then yes, there are several approaches one might take, one of which you've
described below. To my untrained eye, it looks like mechanisms I've seen in
some object-ish C implementations and in POSIX threads, but I haven't used
either enough to really know their ins and outs.

| [text deleted]
|
| Here's the basic plan for an exception system that is mostly clear of
| $SIG{__DIE__}:
|
| catch sub {
| # Code to execute that may throw an exception
| }, FileOpenException => sub {
| # execute this code on a FileOpen exception
| }, finally => sub {
| # execute this code after leaving the code scope, no matter what.
| };
|
| Throw looks like this:
|
| throw FileOpenException; #optional, @moredata;
|
| Inside each of the catch handlers, you can use:
|
| rethrow #optional exception, @moredata;
|
|
| I don't have the internals of catch and throw worked out yet, but the
| basic idea is this: keep a stack of exception actions (with each action
| being a closure), and on an exception (when throw() is invoked)
| _directly_ call the closure that handles that exception, if one exists.
| If no handler is found, the "finally" closure gets executed, and then the
| exception stack is peeled back by one to look for handlers in the next
| scope. Note that _all_ of this is happening within the throw() call, and
| the real stack scope never changes, we are relying on the closures to figure
| out where they belong. It's only after a handler finishes that we figure
| out how far back in the stack we need to be, and _then_ use die() to peel
| back the perl stack.

Sounds basically fine, except that I wouldn't advocate executing the "finally"
block when handling an exception. I think that an exception shouldn't of
itself do anything which would alter the current thread of normal execution, so
that if some handler dismisses the exception, normal execution can resume from
the statement after the C<throw>, with the same state as before the execution
(aside modifications made by the handlers). This isn't to say that the
handlers don't execute in their own scope, and may not be able to see lexicals
in the caller; only that the process of throwing the exception shouldn't close
out the calling scope. (BTW, I'd say that handlers ought to execute in a scope
internal to the caller for purposes of symbol lookup -- they should see the
caller's C<local> variables -- but outside for purposes of handling nested
exceptions -- if a handler throws an exception, it should be passed first to
any handlers the handler established itself, then to handlers established by
the handler's caller's caller, and so on out. (Try that for a
tongue-twister. :-)) The point here is that if the handler throws an
exception, it shouldn't reinvoke itself.

Ideally, I'd want a handler to be able to cause one of four things to happen:
- exception is dismissed; execution resumes in the normal thread at the
statement just after the one which threw the exception
- exception is dismissed; call stack is unwound by a specified number
of frames, and execution is resumed at the statement just after the
last call that was unwound
- exception is passed out to the next handler
- a new exception is thrown, which is handled as a new, "nested" event
If it is eventually dismissed, handling of the current exception
is resumed, as though it were the normal execution path, and
so on . . .

| I must say that, all things considered, closures in perl are a great deal
| of fun. :-)

Indeed.

Regards,
Charles Bailey bailey@genetics.upenn.edu
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
Here's a wacky one:

$ ./perl
$SIG{__DIE__} = sub { goto recover };
die "oops";
recover:
print "wow\n";
^D
wow
oops at - line 2.

Talk about snatching defeat from the jaws of victory...

Larry
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
>Here's a wacky one:
>
> $ ./perl
> $SIG{__DIE__} = sub { goto recover };
> die "oops";
> recover:
> print "wow\n";
> ^D
> wow
> oops at - line 2.
>
>Talk about snatching defeat from the jaws of victory...

Sorta closer, though still a kludge:
$ perl
$SIG{__DIE__} = sub { $__excpt = 0; goto recover; };
die "oops";
recover:
print "wow\n";
END { exit 0 unless $__excpt; }
the idea here being that
if one wants to exit now,
one just doesn't C<goto> a label in the main thread,
elsif one wants to go back to normal,
one sets $__excpt = 0 and executes a C<goto> back into the main thread,
elsif one wants to recover, but report the error out
one sets $__excpt = !0 and executes a C<goto> back into the main thread
endif.

Regards,
Charles Bailey bailey@genetics.upenn.edu
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
On Wed, 13 Sep 1995, Larry Wall wrote:

> Here's a wacky one:
>
> $ ./perl
> $SIG{__DIE__} = sub { goto recover };
> die "oops";
> recover:
> print "wow\n";
> ^D
> wow
> oops at - line 2.
>
> Talk about snatching defeat from the jaws of victory...

That looks like a flushing conflict. But it evidentally isn't reliable
behaviour. I get this with 5.001m (no patches):

wow
àé

> Larry

--
Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
: On Wed, 13 Sep 1995, Larry Wall wrote:
:
: > Here's a wacky one:
: >=20
: > $ ./perl
: > $SIG{__DIE__} =3D sub { goto recover };
: > die "oops";
: > recover:
: > print "wow\n";
: > ^D
: > wow
: > oops at - line 2.
: >=20
: > Talk about snatching defeat from the jaws of victory...
:
: That looks like a flushing conflict. But it evidentally isn't reliable=20
: behaviour. I get this with 5.001m (no patches):
:
: =09wow
: =09=E0=E9

Gad, I hate MIME.

There is a buffer conflict there. The more basic problem is that
there's a runlevel confusion. The "goto" should realize that it has to
longjmp() out of the die, but doesn't. So it ends up doing the
equivalent of

$SIG{__DIE__} = sub { print "wow" };

Larry
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
On Wed, 13 Sep 1995, Charles Bailey wrote:

> Ah. Sorry; I was imprecise in my original statement. As far as I can see,
> $SIG{__DIE__} is the only mechanism extant in Perl from which one could build
> an exception handling mechenism. Perl would have to be modified to allow
> execution to resume if a handler returned an "OK" status, and we'd need to sort
> out actions for "nested" exception chains, but the basic principle is there.
>
> If one is willing to build an exception handling mechanism into Perl de novo,
> then yes, there are several approaches one might take, one of which you've
> described below. To my untrained eye, it looks like mechanisms I've seen in
> some object-ish C implementations and in POSIX threads, but I haven't used
> either enough to really know their ins and outs.

But a closure based exception system doesn't actually require any
_changes_ to the Perl core, merely a module of code. So yes, it has to be
built from scratch, but no, there isn't any particular barrier to doing
so. Since the handlers are executing in the scope of the thrown execption,
returning (resuming) where the exception happened is no problem. And then
normal mechanisms, either die() or return(), can be used to pop stack
frames if a handler needs to end up outside the calling code.

> Sounds basically fine, except that I wouldn't advocate executing the "finally"
> block when handling an exception.

That's one of the things I'm a little fuzzy on. ;-)

> I think that an exception shouldn't of
> itself do anything which would alter the current thread of normal execution, so
> that if some handler dismisses the exception, normal execution can resume from
> the statement after the C<throw>, with the same state as before the execution
> (aside modifications made by the handlers). This isn't to say that the
> handlers don't execute in their own scope, and may not be able to see lexicals
> in the caller; only that the process of throwing the exception shouldn't close
> out the calling scope.

Agreed. I think "finally" actions should be taken when the callers stack
frame is discarded, either via the catch block ending without error or by
an unhandled exception. If you don't have "finally" actions then you end
up doing the same clean-up over in all your exception handlers, and that's
a pain. But having "finally" step on the handler's toes isn't much fun
either.

> (BTW, I'd say that handlers ought to execute in a scope
> internal to the caller for purposes of symbol lookup -- they should see the
> caller's C<local> variables -- but outside for purposes of handling nested
> exceptions -- if a handler throws an exception, it should be passed first to
> any handlers the handler established itself, then to handlers established by
> the handler's caller's caller, and so on out. (Try that for a
> tongue-twister. :-)) The point here is that if the handler throws an
> exception, it shouldn't reinvoke itself.

Thank you for that... I'll get back to you if I ever understand it. :-)

Seriously, I'm not at all sure nested exceptions are needed. Merely being
able to rethrow the original exception, or throw a new exception and have
it continue out of the chain (as if it were originally an unhandled
exception) seems sufficnt. Then again, if this whole thing is done with
closures, fully recursive exception handling might come automatically.

As for the scope of handlers: if they are closures, then they'll see two
scopes, I guess. The scope they were created in, overlayed with any
recent local()'ized changes to that scope. So actually, it looks like not
much of the scope of the catch {} block would be available. So standard
de-allocation handling would probably need to look like this:

$ptr = allocate MassiveObject;
catch sub {
}, finally => sub {
deallocate MassiveObject $ptr;
};

> Ideally, I'd want a handler to be able to cause one of four things to happen:
> - exception is dismissed; execution resumes in the normal thread at the
> statement just after the one which threw the exception

Via a "resume" call. Which probably will trigger a "last", or something.

> - exception is dismissed; call stack is unwound by a specified number
> of frames, and execution is resumed at the statement just after the
> last call that was unwound

This is ideally the behaviour you get when you fall all the end of an
exception handler. You get taken out of the handler and the related catch
{}. I'd also say that a "finally" handler, if one is given, will get
execute somewhere in the middle of this.

> - exception is passed out to the next handler

A rethrow. Probably implemented with a "next", or other magic. A question:
if the next (next innermost, actually) handler "resumes", can it get back
to the code that originally threw the exception? If so, we can't unwind
the call stack (and execute our "finally" blocks) until we know for
certain that that isn't possible. This probably means that a handler might
get some lexical variables it wasn't expecting, if it's called from far
enough "up" the handler chain.

> - a new exception is thrown, which is handled as a new, "nested" event
> If it is eventually dismissed, handling of the current exception
> is resumed, as though it were the normal execution path, and
> so on . . .

Or perhaps this is a rethrow? I've never dealt with a language that
supports resumption of exceptions, so I'm sure I'm missing some
subtleties of implementation here.

But I suppose a handler could include a catch block, complete with it's
own exception handlers, that could, if it contained an unhandled execption
"leak" out to the original exception chain.

> Regards,
> Charles Bailey bailey@genetics.upenn.edu

--
Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
On Wed, 13 Sep 1995, Charles Bailey wrote:

> Sorta closer, though still a kludge:
> $ perl
> $SIG{__DIE__} = sub { $__excpt = 0; goto recover; };
> die "oops";
> recover:
> print "wow\n";
> END { exit 0 unless $__excpt; }
> the idea here being that
> if one wants to exit now,
> one just doesn't C<goto> a label in the main thread,
> elsif one wants to go back to normal,
> one sets $__excpt = 0 and executes a C<goto> back into the main thread,
> elsif one wants to recover, but report the error out
> one sets $__excpt = !0 and executes a C<goto> back into the main thread
> endif.

Good grief, that's frightful. I know perl includes some remanents of
BASIC, but do you really want to build something based on goto's?

> Regards,
> Charles Bailey bailey@genetics.upenn.edu

--
Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
On Wed, 13 Sep 1995, Larry Wall wrote:

> : On Wed, 13 Sep 1995, Larry Wall wrote:
> :
> : > Here's a wacky one:
> : >=20
> : > $ ./perl
> : > $SIG{__DIE__} =3D sub { goto recover };
> : > die "oops";
> : > recover:
> : > print "wow\n";
> : > ^D
> : > wow
> : > oops at - line 2.
> : >=20
> : > Talk about snatching defeat from the jaws of victory...
> :
> : That looks like a flushing conflict. But it evidentally isn't reliable=20
> : behaviour. I get this with 5.001m (no patches):
> :
> : =09wow
> : =09=E0=E9
>
> Gad, I hate MIME.

My, I'm surprised. This is the first time PINE has used quoted-printable.
Or at least the first time I've seen it... Usually I see it when some
digest has been unpacked without MIME headers and I get the =.. garbage.

> There is a buffer conflict there. The more basic problem is that
> there's a runlevel confusion. The "goto" should realize that it has to
> longjmp() out of the die, but doesn't. So it ends up doing the
> equivalent of
>
> $SIG{__DIE__} = sub { print "wow" };

Yes, I can see how that happens. I'm less certain about whether one would
_want_ it to happen. :-)

Also in a slightly related note, I've been slightly worried about what
happens during END {} processing, and whether it might be called inside
STDIO. If that's the case, killing a program that includes C<END {
ReadMode 0; # reset terminal }> via a signal might cause a bit more havoc
then would be expected.

> Larry

--
Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)