Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

Re: Can I catch a die from someone else's module?

by kcott (Archbishop)
on Apr 18, 2022 at 19:59 UTC ( [id://11143063]=note: print w/replies, xml ) Need Help??


in reply to Can I catch a die from someone else's module?

G'day bartender1382,

I had a look in Spreadsheet::Read but can't find the "If a file cannot be found ..." message you reported. Perhaps it's not an error message but private feedback from the module's author. Regardless, I have no context for the die() or what it's reporting.

Having said that, I suspect what you want is eval. Compare the following two short pieces of code and their output.

Here's the type of scenario I think you're dealing with:

#!/usr/bin/env perl use strict; use warnings; package Module::That::Dies; sub die_here { die "RIP Module::That::Dies" } package main; Module::That::Dies::die_here(); print "main continues ...\n";

Output:

RIP Module::That::Dies at ./pm_11143055_trap_mod_errors.pl line 8.

Here's a modification of that code to do what I think you want:

#!/usr/bin/env perl use strict; use warnings; package Module::That::Dies; sub die_here { die "RIP Module::That::Dies" } package main; eval { Module::That::Dies::die_here(); 1; } or do { warn "Error from Module::That::Dies:\n$@\n"; }; print "main continues ...\n";

Output:

Error from Module::That::Dies: RIP Module::That::Dies at ./pm_11143055_trap_mod_errors.pl line 8. main continues ...

If that's not what you want, please provide more context for the problem to help us to help you.

— Ken

Replies are listed 'Best First'.
Re^2: Can I catch a die from someone else's module?
by haukex (Archbishop) on Apr 18, 2022 at 20:07 UTC
    eval { Module::That::Dies::die_here(); 1; } or do { warn "Error from Module::That::Dies:\n$@\n"; };

    bartender1382: I just wanted to highlight that eval { ...; 1 } or do { ... } is indeed the correct pattern to use, instead of the unfortunately still common eval ...; if ($@) - see Bug in eval in pre-5.14 and my reply Re: Bug in eval in pre-5.28. In fact, this use of eval is very similar in function to Try::Tiny. The latter just has a few small advantages as described in its documentation, while the eval solution has the advantage that it is pure Perl built-in (Update: Try::Tiny is pure Perl too, but not a core module).

Re^2: Can I catch a die from someone else's module?
by bartender1382 (Beadle) on Apr 19, 2022 at 18:41 UTC

    Yes, eval definitely works!

    Quick followup:

    Do I need the 1; ? It works with and without it, just wanted to make sure it might not be needed for something internal, or was it there for an example?

    eval { Module::That::Dies::die_here(); 1; } or do { warn "Error from Module::That::Dies:\n$@\n"; };

      Do I need the 1; ?

      Generally, yes, you should include it. The reason is that eval returns undef on failure, which is what the or do { ... } is intended to react to. However, the or would also be triggered if the eval block were to return any other false value, such as 0 or the empty string. For example, the following incorrectly prints "Error from Module::That::Dies:". So unless you can be absolutely sure that the eval block always returns a true value, you should include the 1 (or any other true value) as the last statement of the block.

      sub Module::That::Dies::die_here { return 0 } eval { Module::That::Dies::die_here(); #1; } or do { warn "Error from Module::That::Dies:\n$@\n"; };

      Update: I tend to write it like the following, since the 1 on a line by itsself can look out of place and might be accidentally deleted:

      eval { ... ;1 } or do { # catch ... }

        I, too, use the eval { ...; 1; };. I'm literally just writing unit tests with eval right now, so I thought I'd share how I often write them:

        my $missing_opt_code_succeeded = eval { $tesla->option_codes('NON_EXIST'); 1; }; is $missing_opt_code_succeeded, undef, "If an option code doesn't exist, we croak ok"; like $@, qr/does not exist/, "...and error message is sane";
      "Do I need the 1;?"

      ++ Good question.

      I would always include it. If you think other maintainers may not understand its importance, add a comment like:

      eval { ...; 1; # IMPORTANT! Do not remove. See: https://www.perlmonks.org/?nod +e_id=11143055 } or do { ...; };

      Even in situations when the last statement in the eval block evaluates to 1, or some other TRUE value, I would include it:

      eval { ...; $x = 1; 1; } ...;

      Otherwise, if someone removes the '$x = 1;' line, or changes the value, but does not know, or forgets, to add the '1;' statement, the 'eval {...} or do {...};' construct may be broken.

      — Ken

      I think it depends; for this module I would do this since it returns the reference if successful.
      local $@; my $book = eval { Spreadsheet::Read->new($file); };
      or
      local $@; my $book; my $ok = eval { $book = Spreadsheet::Read->new($file); 1; };
      The second example seems like "more work" to handle the error and is a lot messier. So in this case adding the "1" is superfulous since the called sub actually returns something (or doesn't).

      A case where I'd use 1; with an or undef thrown in:

      local $@; my $ok = eval { doSomethingButDontWantReturnValButCouldDie() or undef; 1; };
      I think ultimately, the answer is like I stated above, it depends - on what you're doing and expecting; and how you tend to check for/handle exceptions.

      I've also done this; but usually it's a game time decision for me.

      local $@; my $ok = eval { doSomethingButDontWantReturnValButCouldDie(); 1; } or undef;
      I'd like to add as a separate comment, while the use if the 1; is "it depends"; I would absolutely always localize $@ as close in scope to the eval {} as make sense; usually right before it (unless it's already been done in the same scope and if there are a series of eval{}s that have already been successfully executed.
      local $@; my $ok = eval { doSomethingButDontWantReturnValButCouldDie() or undef; 1; };

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://11143063]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others goofing around in the Monastery: (5)
As of 2024-04-25 16:59 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found