Perl unexpected behavior: croak vs. try catch - perl

I had seen some exceptions that pointed to (end of) the catch block itself (see the example below).
As my opinion, this is an unexpected behavior, since it alters the location of original exception and make difficult to debug (it should say die at line 13.)
It shows the (correct) line 13, if I use die/confess or using eval instead try-catch.
Not knowing how my code will be called within the stack, I started to avoid using croak now. What do you think? Did I get right, or there is a way to improve this?
Best regards, Steve
use Carp;
use Try::Tiny;
try {
foo();
}
catch {
# do something before die
die $_;
}; # this is line 10
sub foo {
croak 'die'; # this is line 13
}
Output:
die at line 10.

This is the intended behavior from Carp
[...] use carp() or croak() which report the error as being from where your module was called. [...] There is no guarantee that that is where the error was, but it is a good educated guess.
So the error is reported at where the module's sub is called, which is what the user wants
use warnings;
use strict;
use feature 'say';
use Try::Tiny;
package Throw {
use warnings;
use Carp qw(croak confess);
#sub bam { die "die in module" }; # l.11
sub bam { croak "croak in module" };
1;
};
try {
Throw::bam(); # l.17
}
catch {
say "caught one: $_";
die "die in catch: $_";
};
say "done";
Prints
caught one: croak in module at exceptions.pl line 17.
die in catch: croak in module at exceptions.pl line 17.
If the sub throws using die then this is reported at line 11, what is the normal behavior of die, and what you seem to expect.
If any of this is unclear or suboptimal then better use confess and nicely get a full stacktrace. Also, if you wish more exception-based-like code behavior, can put together an exception/error class and throw its object,† designed and populated as desired.
If you want to confess an object note that at this time Carp has limits with that
The Carp routines don't handle exception objects currently. If called with a first argument that is a reference, they simply call die() or warn(), as appropriate.
One way then would be to confess a stringification of the object,‡ getting at least both a full stack backtrace and whatever is in the object.
I get the same behavior with eval, by replacing try-catch and $_ above
eval {
Throw::bam();
};
if ($#) {
say "caught one: $#";
die "die in catch: $#";
};
Prints exactly the same as above
While the above is clear and behaves as expected, a weird thing is indeed seen in the question's example: the error is reported from the whole try-catch statement, ie. at its closing brace, where line 10 is. (The try sub is prototyped and the whole try-catch is a syntax aid equivalent to a call to try that takes an anonymous sub, and then perhaps more. See ikegami's comment, and docs. Also see this post for more about its syntax.)
This is strange since the call to the croaking sub is foo() inside the try statement and this line should be reported, what can be confirmed by running the script with -MCarp::Always. But in the code in this answer the line of the call to Throw::bam is indeed reported -- why this difference?
The clear purpose of croak is to be used in the libraries, so that the user can see at which point in their (user's) code they called the library in a way that triggered an error. (While die would point to the place where error is detected, so in the library, most likely useless to the user. But read die and Carp docs for related complexities.)
What isn't obvious is that when croak is emitted in the same namespace (main::foo()) from try-catch in its own namespace (Try::Tiny) things get confused, and the end of its statement is reported. This can be checked by adding a foo() to my code above and calling it (instead of a sub from a module), and we get the question's behavior reproduced.
This doesn't happen if main::foo() with croak inside is called from a (complex) statement right in main::, so it seems to be due to the try-catch mix up of namespaces. (On the other hand, try-catch sugar adds an anonymous sub to the callstack, and this sure can mix things up as well.)
In practical terms, I'd say: always use croak out of modules (otherwise use die), or, better yet if you want to mimic exception-based code, use confess and/or your exception class hierarchy.
† Even just like die ExceptionClass->new(...);
Bear in mind that in the way of exceptions Perl only has the lonesome die, and eval. For more structure you'll need to implement it all, or use frameworks like Exception::Class or Throwable
‡ By writing and using a method that generates a plain string with useful information from the object, for Carp::confess $obj->stringify.
Or by overloading the "" (quote) operator for the class since it gets used when confess-ing an object (string context), for Carp::confess $obj; this is good to have anyway.
A basic example for both:
use overload ( q("") => \&stringify );
sub stringify {
my $self = shift;
join ", ", map { "$_ => " . ( $self->{$_} // 'undef' ) } keys %$self
}
where instead of a reference to a named sub on can directly write an anonymous sub.

As a way of solving the OP's problem, but with a different module, if you use Nice::Try instead, you will get the result you expect:
use Carp;
use Nice::Try;
try {
foo();
}
catch {
# do something before die
die $_;
} # this is line 10
sub foo {
croak 'die'; # this is line 13
}
You get:
die at ./try-catch-and-croak.pl line 13.
main::foo() called at ./try-catch-and-croak.pl line 4
main::__ANON__ called at ./try-catch-and-croak.pl line 7
eval {...} called at ./try-catch-and-croak.pl line 7 ...propagated at ./try-catch-and-croak.pl line 9.
For full disclosure, I am the author behind Nice::Try

Related

How to Test::More and smarter with Transactions?

Currently I am creating transactional tests like that:
use Test::More;
use Try::Tiny;
my $dbh = ...;
subtest 'do something envolving a transaction' => sub {
$dbh->begin_work();
try {
my $obj = create_in_db({...}, $dbh);
my $result = MyTestObject->new()->do_something($obj);
ok $result "We've got great results";
} catch {
croak $_;
} finally {
$dbh->rollback(); #kills $obj
};
};
done_testing();
1;
This works, but has the disadvantage, that the line of the error is always the catch block and the end of the subtest, never where the error actually happens. And it is a lot of boring boilerplate code that quickly adds up.
How to do this in a smarter way?
The fact that the error (croak) is reported at the end of try-catch-finally blocks† instead of where the offending code is called seems due to Try::Tiny's mixup with namespaces; see a discussion in this post and comments. The exact source of this misbehavior isn't clear to me in the complex try sub. A simple demo
use warnings;
use strict;
use feature 'say';
use Carp qw(croak);
use Try::Tiny;
sub this_croaks { croak "ouch from a sub in ", __PACKAGE__ } # line 8
try {
this_croaks(); # line 11
}
catch { print "In try: $_" }
finally { say "clean up" }; # line 14
This prints
In try: ouch from a sub in main at try_tiny_mixup.pl line 14.
clean up
But the croak-ing sub is called at line 11 so that should be reported, not line 14.‡
Changing croak to die makes it print line 8 (what of course isn't a solution) while using eval instead of Try::Tiny results in the correct line 11 printed (what is a valid solution). See the linked post. I am not aware of a fix with Try::Tiny but there are drop-in replacements, see below.
I don't see that this in any way depends on what tests are performed (here involving a database transaction as we are told). And I cannot check more specifically without a runable example.
The one thing that works fully is to revert to eval, which since 5.14 isn't anymore borne with subtleties that were the stated reason for Try::Tiny. Like
eval {
this_croaks();
};
if ($#) {
print "In eval: $#";
}
say "clean up";
This is still archaic but it works just as intended (and Try::Tiny comes with twists of its own).
Hopefully the coming native try/catch, introduced as experimental in 5.34.0, won't have problems like this.§ For now it doesn't
use warnings;
use v5.34.0;
use Carp qw(croak);
use feature 'try';
no warnings qw(experimental::try);
sub this_croaks { croak "ouch from a sub in ", __PACKAGE__ } # line 9
try {
this_croaks(); # line 12
}
catch ($e) {
print "In try: $e";
}
say "clean up"; # there is no "finally" keyword
This correctly pegs it as called at line 12 (and coming from line 9). Note that there is no finally keyword yet. The module Syntax::Keyword::Tiny (see footnote) does have it so it may be possible to use it as a drop-in replacement for Try::Tiny.
I suspect that clearing this up will clear up the test's behavior as well. (But I didn't get to test that.)
† Syntax aids ("sugar") for anonymous subs (which in many ways aren't so naive)
‡ Submitted a bug report
§ This is getting ported from Syntax::Keyword::Try by the author themselves so you may want to try that -- but then better use Feature::Compat::Try, they say. See docs of both, and see its tracker.
Once we are at experimental stuff see perlexperiment.

Wrapping Perl "die" and "warn" in a utility subroutine

I want to write a small subroutine that can decorate all error messages in a consistent way instead of having to copy it all around my program.
However I want the line numbers to be from where it was called, not from where the die/warn occurred.
In C I would just use a preprocessor macro, but Perl does not have those. What is the best way to implement this?
Use Carp for warnings/errors. You can use __WARN__ and __DIE__ hooks to affect what warn prints to the STDERR stream and how die is thrown. Note that they are quite different.
use warnings;
use strict;
use feature 'say';
use Carp;
$SIG{__WARN__} = \&wrap_warn;
sub wrap_warn {
print "WARNING: #_";
}
sub level_2 {
say "Print from level_2";
carp "carp from level_2(#_)";
}
sub level_1 {
level_2(#_);
}
level_1("from main");
prints to STDOUT
Print from level_2
WARNING: carp from level_2(from main) at wrap_warn.pl line 19.
main::level_2('from main') called at wrap_warn.pl line 15
main::level_1('from main') called at wrap_warn.pl line 22
If you want this to still go to STDERR then use print STDERR "WARNING: #_";
Make sure to carefully read about %SIG in perlvar and warn, at least.
While it seems that you want this to be global, I'd like to mention that one generally wants to local-ize changes like this one. There's an example in this post, and more out there.
Adding the following will add stack traces to exceptions and warnings:
use Carp::Always;
For the occasional use, use the following to avoid modifying your program:
perl -MCarp::Always script args
or
PERL5OPT=-MCarp::Always script args

Prevent strings from being interpreted as a file handle

Perl has the feature that strings named like a file handle are taken to be a filehandle:
# let this be some nice class I wrote
package Input {
sub awesome { ... }
}
So when we do Input->awesome or extra-careful: 'Input'->awesome, the method will get called. Unless:
# now somewhere far, far away, in package main, somebody does this:
open Input, "<&", \*STDIN or die $!; # normally we'd open to a file
This code doesn't even have to be executed, but only be seen by the parser in order to have Perl interpret the string 'Input' as a file handle from now on. Therefore, a method call 'Input'->awesome will die because the object representing the file handle doesn't have awesome methods.
As I am only in control of my class but not of other code, I can't simply decide to only use lexical filehandles everywhere.
Is there any way I can force Input->awesome to always be a method call on the Input package, but never a file handle (at least in scopes controlled by me)? I'd think there shouldn't be any name clash because the Input package is actually the %Input:: stash.
Full code to reproduce the problem (see also this ideone):
use strict;
use warnings;
use feature 'say';
say "This is perl $^V";
package Input {
sub awesome {
say "yay, this works";
}
}
# this works
'Input'->awesome;
# the "open" is parsed, but not actually executed
eval <<'END';
sub red_herring {
open Input, "<&", \*STDIN or die $!;
}
END
say "eval failed: $#" if $#;
# this will die
eval {
'Input'->awesome;
};
say "Caught: $#" if $#;
Example output:
This is perl v5.16.2
yay, this works
Caught: Can't locate object method "awesome" via package "IO::File" at prog.pl line 27.
Using the same identifier for two different things (a used class and filehandle) begs for problems. If your class is used from a different class that's used in the code that uses the filehandle, the error does not appear:
My1.pm
package My1;
use warnings;
use strict;
sub new { bless [], shift }
sub awesome { 'My1'->new }
__PACKAGE__
My2.pm
package My2;
use warnings;
use strict;
use parent 'My1';
sub try {
my $self = shift;
return ('My1'->awesome, $self->awesome);
}
__PACKAGE__
script.pl
#!/usr/bin/perl
use warnings;
use strict;
use My2;
open My1, '<&', *STDIN;
my $o = 'My2'->new;
print $o->awesome, $o->try;
Using the bareword Input as a filehandle is a breach of the naming convention to have only uppercase barewords for FILEHANDLEs and Capitalized/CamelCased barewords for Classes and Packages.
Furthermore lexcial $filehandles have been introduced and encouraged already a very long time ago.
So the programmer using your class is clearly misbehaving, and since namespaces are per definition global this can hardly be addressed by Perl (supporting chorobas statement about begging for problems).
Some naming conventions are crucial for all (dynamic) languages.
Thanks for the interesting question though, the first time I see a Perl question in SO I would preferred to see on perlmonks! :)
UPDATE: The discussion has has been deepened here: http://www.perlmonks.org/?node_id=1083985

Why do I need to localize $# before using eval?

I'm aware of the fact that $# is a global variable, still I can't figure out why I need to localize it before using eval:
For instance:
eval { SOME_FUNC_THAT_MAY_DIE(); };
if ($#) {
print "An error occured!\n";
}
The only possible thing I can think of is, if some signal handler will call die at the same time I try to read $#, what am I missing here?
The reason to say local $# before calling eval is to avoid stepping on your caller's $#. It's rude for a subroutine to alter any global variables (unless that's one of the stated purposes of the subroutine). This isn't really an issue with top-level code (not inside any subroutine).
Also, on older Perl's, any eval called during object destruction would clobber the global $# (if the object was being destroyed because an exception was being thrown from an eval block) unless $# was localized first. This was fixed in 5.14.0, but many people are still running older Perls.
The Try::Tiny module documentation gives the rationale (as well as providing an alternative):
When you run an eval block and it succeeds, $# will be cleared, potentially clobbering an error that is currently being caught.
This causes action at a distance, clearing previous errors your caller may have not yet handled.
$# must be properly localized before invoking eval in order to avoid this issue.
More specifically, $# is clobbered at the beginning of the eval, which also makes it impossible to capture the previous error before you die (for instance when making exception objects with error stacks).
You don't need to, but if you wrote code like this, localizing $# would keep the first error as it was. and if you didn't write code like this, the local $# would have no effect. better would be to handle errors before running any extra code.
eval {
die "error 1\n";
};
foo();
print "processing $#\n";
sub foo {
#local $#;
eval {
die "error 2\n";
};
}

How can I get around a 'die' call in a Perl library I can't modify?

Yes, the problem is with a library I'm using, and no, I cannot modify it. I need a workaround.
Basically, I'm dealing with a badly written Perl library, that exits with 'die' when a certain error condition is encountered reading a file. I call this routine from a program which is looping through thousands of files, a handful of which are bad. Bad files happen; I just want my routine to log an error and move on.
IF I COULD modify the library, I would simply change the
die "error";
to a
print "error";return;
, but I cannot. Is there any way I can couch the routine so that the bad files won't crash the entire process?
FOLLOWUP QUESTION: Using an "eval" to couch the crash-prone call works nicely, but how do I set up handling for catch-able errors within that framework? To describe:
I have a subroutine that calls the library-which-crashes-sometimes many times. Rather than couch each call within this subroutine with an eval{}, I just allow it to die, and use an eval{} on the level that calls my subroutine:
my $status=eval{function($param);};
unless($status){print $#; next;}; # print error and go to next file if function() fails
However, there are error conditions that I can and do catch in function(). What is the most proper/elegant way to design the error-catching in the subroutine and the calling routine so that I get the correct behavior for both caught and uncaught errors?
You could wrap it in an eval. See:
perldoc -f eval
For instance, you could write:
# warn if routine calls die
eval { routine_might_die }; warn $# if $#;
This will turn the fatal error into a warning, which is more or less what you suggested. If die is called, $# contains the string passed to it.
Does it trap $SIG{__DIE__}? If it does, then it's more local than you are. But there are a couple strategies:
You can evoke its package and override die:
package Library::Dumb::Dyer;
use subs 'die';
sub die {
my ( $package, $file, $line ) = caller();
unless ( $decider->decide( $file, $package, $line ) eq 'DUMB' ) {
say "It's a good death.";
die #_;
}
}
If not, can trap it. (look for $SIG on the page, markdown is not handling the full link.)
my $old_die_handler = $SIG{__DIE__};
sub _death_handler {
my ( $package, $file, $line ) = caller();
unless ( $decider->decide( $file, $package, $line ) eq 'DUMB DIE' ) {
say "It's a good death.";
goto &$old_die_handler;
}
}
$SIG{__DIE__} = \&_death_handler;
You might have to scan the library, find a sub that it always calls, and use that to load your $SIG handler by overriding that.
my $dumb_package_do_something_dumb = \&Dumb::do_something_dumb;
*Dumb::do_something_dumb = sub {
$SIG{__DIE__} = ...
goto &$dumb_package_do_something_dumb;
};
Or override a builtin that it always calls...
package Dumb;
use subs 'chdir';
sub chdir {
$SIG{__DIE__} = ...
CORE::chdir #_;
};
If all else fails, you can whip the horse's eyes with this:
package CORE::GLOBAL;
use subs 'die';
sub die {
...
CORE::die #_;
}
This will override die globally, the only way you can get back die is to address it as CORE::die.
Some combination of this will work.
Although changing a die to not die has a specific solution as shown in the other answers, in general you can always override subroutines in other packages. You don't change the original source at all.
First, load the original package so you get all of the original definitions. Once the original is in place, you can redefine the troublesome subroutine:
BEGIN {
use Original::Lib;
no warnings 'redefine';
sub Original::Lib::some_sub { ... }
}
You can even cut and paste the original definition and tweak what you need. It's not a great solution, but if you can't change the original source (or want to try something before you change the original), it can work.
Besides that, you can copy the original source file into a separate directory for your application. Since you control that directory, you can edit the files in it. You modify that copy and load it by adding that directory to Perl's module search path:
use lib qw(/that/new/directory);
use Original::Lib; # should find the one in /that/new/directory
Your copy sticks around even if someone updates the original module (although you might have to merge changes).
I talk about this quite a bit in Mastering Perl, where I show some other techniques to do that sort of thing. The trick is to not break things even more. How you not break things depends on what you are doing.