where is perl eval "...propagated" documented

163 Views Asked by At

In the following code, eval checks whether an expression is valid. It captures an exception, and my code prints out the exception, without the code dying at that point. So far, so good.

But when a die; expression is subsequently encountered, the exception text is printed out again, without my asking for it, with the addition of a ...propagated message, giving the line number of the die; command. But at this point, the exception text is inappropriate and confusing. It seems that perl holds onto the eval error message, or exception message, until we reach a die;.

Below the code posted below are two workarounds, either of which makes the behavior go away.

Where is this particular behavior documented? What's the thinking behind it?

#!/usr/bin/perl
use strict; use warnings;
my $str=q/(d/;
my $rgx;
eval{$rgx=qr/$str/};
if(length $@)
{
   print join('', 'qr/', $str, '/ does not compile: ',"\n", $@, );
}
print "Got past eval. But next, at 'die;', it will print an error message that no longer pertains.\n";
die;

Workaround (1). Give die; a nonempty string:

#!/usr/bin/perl
use strict; use warnings;
my $str=q/(d/;
my $rgx;
eval{$rgx=qr/$str/};
if(length $@)
{
   print join('', 'qr/', $str, '/ does not compile: ',"\n", $@, );
}
print "Got past eval. Next, the nonempty string in die ' '; flushes out the inappropriate exception message.\n";
die ' ';

Workaround (2). Execute another eval which does not find a syntax error:

#!/usr/bin/perl
use strict; use warnings;
my $str=q/(d/;
my $rgx;
eval{$rgx=qr/$str/};
if(length $@)
{
    print join('', 'qr/', $str, '/ does not compile: ',"\n", $@, );
}
print "got past eval\n";
$str=0;
eval{$rgx=qr/$str/};
die;

2

There are 2 best solutions below

1
zdim On BEST ANSWER

It's fairly logical behavior, I'd say, with die used without arguments. What is it supposed to do?

Documented in die

If LIST was empty or made an empty string, and $@ already contains an exception value (typically from a previous eval), then that value is reused after appending "\t...propagated". This is useful for propagating exceptions:

eval { ... };
die unless $@ =~ /Expected exception/;

[...]

So issuing an unrelated die without any arguments gets mixed up in this facility.

0
ikegami On

You need to provide an error message to die. If you don't, this is one of the possible documented outcomes.

If LIST was empty or made an empty string, and $@ already contains an exception value (typically from a previous eval), then that value is reused after appending "\t...propagated". This is useful for propagating exceptions:

eval { ... };
die unless $@ =~ /Expected exception/;

If you want to exit without printing anything, you want exit.

exit( $! || ( $? >> 8 ) || 255 );   # The value that `die` uses.

However, the following is a better and far more idiomatic solution:

my $rgx = eval { qr/$str/ }
   or die("Can't compile qr/$str/: $@");