in reply to Best practices for handling exceptions in die/eval style

I always do things like this:

my $ok = eval { do_something(); 1 }; if (! $ok){ handle_exception(); # possibly use contents of $@ }

If I'm only doing one thing in the if block, I often will write it more compactly:

handle_exception() if ! $ok;

Sometimes I just want to croak with a separate message instead of the one generated by (perhaps not even) my code:

croak "damned module failed with a confusing error\n" if ! $ok;

These types of things are found all over my test suites. Here's one example from one of my CPAN distributions.

What this does, is if the function/method called inside the eval dies/croaks, eval returns undef. If it succeeds, it returns 1/true.

Replies are listed 'Best First'.
Re^2: Best practices for handling exceptions in die/eval style
by krautcat (Acolyte) on Aug 29, 2018 at 22:05 UTC

    I used similar tactics:

    eval { # here we try do_smth() } or { # here we catch ... }

    But what is about $@ clobbering? I read in MVP book about it and it seems legit that we can clobber global variable. Now I find their code right:

    # Try clause my ($error1, $error2); { local $@; unless (eval { ...; return 1 }) { $error1 = 1; $error2 = $@; } } # Catch clause if ($error1) { # handle exception }

      Clobbering is why, years ago, I changed to the tactic I use now. The $@ can be clobbered in some certain circumstances. The return 1; is the equivalent of just having 1;... the block will return the last expression evaluated (1) without the explicit return().

      If you get undef, you know that eval failed (ie. die()d), regardless of/if $@ was populated or not. Localizing $@ is definitely a wise idea if that's the route one wants to take, but it's too much code for me. Keep subs and tests tight and small, and you should be able to know what the problem is specifically, without the need of $@'s contents (that definitely isn't a hard rule by any stretch, so take with a grain of salt).

        I appreciate your tactic and I can understand it.

        But it's confusing for me to ignore $@'s contents, I have some Python and C++ background so I prefer to create objects not messages. What if your object's method or object calls eval in somebody's exception handler code but it's not yours?

        When using exceptions as a method of propagating failure, as opposed to checking returns codes at every level for instance, it's very useful to know what error message or error object is in $@ in order to correctly deal with it (either in the error handling code itself at a higher level, or when you check the logs later). The defensive localization of $@ is important when your code could possibly be called from, for instance, a DESTROY sub of an object that gets destroyed while going out of a scope due to an exception being thrown.