Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Try::Tiny and $SIG{__DIE__} in perl?

Tags:

perl

Is it possible to use Try::Tiny in a Perl program that has a 'overloaded' $SIG{__DIE__}? For example, the desired output of this program would be "caught it":

#!/usr/bin/perl
use strict;
use warnings;
use diagnostics;
use Try::Tiny;

# here how to deal with try and catch 
$SIG{__DIE__} =
  sub { 
       print "died my way $_[0]"
};

my $rv;
try {die "its only a flesh wound"; }
catch { 
    $rv = undef; 
    print "caught it: $_ ";
};

Thanks for looking and any advice!

like image 744
turtle Avatar asked Mar 16 '21 23:03

turtle


2 Answers

The docs for $SIG{__DIE__} show $^S being used for a reason: You almost always want to use $^S in __DIE__ handlers to avoid the problem you are asking about.

For example,

#!/usr/bin/perl
use strict;
use warnings;

use Try::Tiny;

$SIG{__DIE__} = sub {
   return if $^S;                      # If in eval.
   print(STDERR "Died: $_[0]");        # Send msg to STDERR, not STDOUT.
   exit( $! || ( $? >> 8 ) || 255 );   # Emulate die().
};

try {
   die("It's only a flesh wound.");
} catch {
   print("Caught: $_");
};

die("More than a flesh wound");

print("done.\n");

outputs

Caught: It's only a flesh wound. at a.pl line 14.
Died: More than a flesh wound at a.pl line 19.
like image 139
ikegami Avatar answered Sep 27 '22 16:09

ikegami


Try::Tiny is mostly a syntactic sugar wrapper for an eval call, and a die call inside an eval block will call a $SIG{__DIE__} handler. The authors anticipated your objection, but ultimately decided to stick with the legacy behavior.

Though it can be argued that $SIG{__DIE__} should be disabled inside of eval blocks, since it isn't people have grown to rely on it. Therefore in the interests of compatibility, try does not disable $SIG{__DIE__} for the scope of the error throwing code.

But feel free to disable it yourself

try {
   local $SIG{__DIE__};
   ...
} catch { ... };

or rewrite try .. catch to do what you want.

sub my_try (&;@) {
    my ($try, @code_refs) = @_;
    local $SIG{__DIE__};
    Try::Tiny::try($try,@code_refs);
}
like image 45
mob Avatar answered Sep 27 '22 16:09

mob