DouglasDD has asked for the wisdom of the Perl Monks concerning the following question:

A common idiom for eval is
eval { do_something_that_might_die(); 1; } or do { my $error = $@ || 'Zombie error'; deal_w($error) || die; }

Is that because $@ might contain something "false-y" (like 0, '0', "", undef)?
(If so, who cares? Why would I care if the "reason string" is false-y or not?)

Or is it a hold-over from bugs in ancient versions of perl?
If so, how old? if we already require versions greater than $v can we dispense with it?

((Sorry monks, I'm sure this has been asked before, but searches like "perl eval zombie error" and the like are mostly about zombie processes and code that already contains that boilerplate.))

Edit: I Forgot to mention that our local coding standards discourage Try::Tiny apparently because it's edge cases have been tripped over in the past.

Replies are listed 'Best First'.
Re: eval: Why use the 'Zombie error' idiom?
by Corion (Patriarch) on Oct 18, 2019 at 09:50 UTC

    Try::Tiny claims that up to 5.14, $@ was cleared at the beginning of the eval { block.

    I think that also a destructor containing eval { can clear out $@, so the above idiom is necessary.

    Using (for example) Try::Tiny helps avoiding that.

      ...So, would local-izing $@ be enough to work-around other code's evals messing with our own $@?
      { # scope the `local` local $@; eval { do_something_that_might_die(); 1; } or do { my $error = $@; ## ?? No need for || 'Zombie error' ?? deal_w($error) || die; } }

        The docs for eval suggest this idiom:

        # alter $@ on nefarious repugnancy only { my $e; { local $@; # protect existing $@ eval { test_repugnancy() }; # $@ =~ /nefarious/ and die $@; # Perl 5.14 and higher only $@ =~ /nefarious/ and $e = $@; } die $e if defined $e }

        I don't know - from the discussion in Try::Tiny, it sounds like that, but then, the code of Try::Tiny isn't really that large either. So maybe looking there (or in its test suite) helps find the nasty edge cases.

      Forgot to mention that our local coding standards discourage Try::Tiny apparently because it's edge cases have been tripped over in the past.

        Interesting choice. I use Try::Tiny precisely to avoid having to work around the edge cases inherent in eval. YMMV, of course.

Re: eval: Why use the 'Zombie error' idiom?
by haukex (Archbishop) on Oct 18, 2019 at 11:24 UTC

    See Bug in eval in pre-5.14 and the replies, there were/are a few remaining issues even after the major bug was fixed, it seems not until 5.28 - and I'd not trust the eval { ... }; if ($@) { ... } pattern anyway. So I'd always use the eval { ...; 1 } or do { ... } idiom without relying on $@.

Re: eval: Why use the 'Zombie error' idiom?
by Anonymous Monk on Oct 18, 2019 at 10:18 UTC
Re: eval: Why use the 'Zombie error' idiom?
by jcb (Parson) on Oct 18, 2019 at 22:55 UTC

    The pattern I am using in the WARC test suite is to set a lexical before entering the eval and to change its value after the code that is expected to throw an exception, like so:

    { my $fail = 0; eval {new WARC::Fields (WARC_Type => 'warcinfo', BOGUS => undef); $fail = 1;}; ok($fail == 0 && $@ =~ m/key without value/, 'reject construction with missing value'); $fail = 0; eval {new WARC::Fields (WARC_Type => 'warcinfo', '::Bogus' => 1); $fail = 1;}; ok($fail == 0 && $@ =~ m/invalid field name/, 'reject construction with field name with actual leading colon' +); # more tests elided... }

    This depends on what you are trying to verify; in the code above, the expected result is "execution does not continue past the bad call", but the same approach can be used to ensure that execution reaches the end of an eval block.

    Back on topic, 'Zombie error' is an example of defensive programming: if the error handling do is reached, the eval must not have reached the end, because the last expression is a true constant, so there should be an error in $@. If $@ is empty, at least two things are wrong: the eval did not complete, and no reasonable error was produced.

Re: eval: Why use the 'Zombie error' idiom?
by cavac (Prior) on Oct 21, 2019 at 15:00 UTC

    In the few cases i am forced to use eval, i usually do something like this:

    my $ok = 0; eval { do_something_that_might_die(); $ok = 1; }; if(!$ok) { shout_at_user(); }

    This way, i don't have to deal with the error message. And in my personal opinion, it's much more readable. The downside, of course, is that Perl::Critic shouts at you - a lot.

    perl -e 'use MIME::Base64; print decode_base64("4pmsIE5ldmVyIGdvbm5hIGdpdmUgeW91IHVwCiAgTmV2ZXIgZ29ubmEgbGV0IHlvdSBkb3duLi4uIOKZqwo=");'