perldoc -v $!
:
When referenced, $!
retrieves the current value of the C "errno
"
integer variable. If $!
is assigned a numerical value, that value
is stored in "errno". When referenced as a string, $!
yields the
system error string corresponding to "errno
".
... Assignment to $!
is similarly ephemeral. It
can be used immediately before invoking the "die()
" operator, to
set the exit value, or to inspect the system error string
corresponding to error n
, or to restore $!
to a meaningful state. (emphases mine)
That explains why you can't do the obvious:
#!/usr/bin/env perl
say_hi() or die "ERROR: sub say_hi had an issue: Details => $!\n";
sub say_hi{
my ($name) = @_;
unless ($name) {
$! = 'no name';
return;
}
print "Hi $name\n";
return 1;
}
That results in:
ERROR: sub say_hi had an issue: Details =>
Consider using eval
/$@
:
#!/usr/bin/env perl
eval { say_hi() } or die "ERROR: sub say_hi had an issue: Details => $@\n";
sub say_hi{
my ($name) = @_;
$name or die "no name\n";
print "Hi $name\n";
return 1;
}
See also "Is Try::Tiny still recommended for exception handling in Perl 5.14 or later?"
If you follow brian's recommendation in this answer to that question, you can do something like:
#!/usr/bin/env perl
use strict;
use warnings;
my $r = say_hi();
$r->{success}
or die sprintf "ERROR: sub say_hi had an issue: Details => %s\n", $r->{reason};
sub say_hi{
my ($name) = @_;
$name or return { success => 0, reason => 'Missing "name"' };
print "Hi $name\n";
return { success => 1 };
}
Or, you can use Params::Validate or Validate::Tiny etc.