Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

Unexpected action at a distance with use warnings FATAL=>'all';

by demerphq (Chancellor)
on Jan 20, 2006 at 11:47 UTC ( #524451=perlmeditation: print w/replies, xml ) Need Help??

I had an interesting glitch occur to me today. I had some code like

eval { for my $case ( @cases ) { if (!interesting($case)) { next; } process($case); } };

The problem was that both interesting() and process() would die for certain error cases. And instead of skipping all the cases on first error i wanted to see all the errors, so I changed to code to something like this:

for my $case ( @cases ) { eval { if (!interesting($case)) { next; } process($case); }; if ($@) { print "$case had errors:$@"; } }

I was a little surprised to discover that now all of my cases were failing. What took me a while to work out was that I had

use warnings FATAL=>'all';
in the code. Nexting out of an eval is a warning, and by promoting the warnings to a fatal the resulting behaviour of the code was fundamenetally changed.

So next time you decide to use warnings fatal do yourself a favour and do a code review of any evals that you are using. Heres an example of the issue.

#!perl -l $|++; use strict; use warnings; use warnings FATAL => 'all'; no warnings 'exiting'; # comment this out to change behaviour. { eval { next }; print "foo" } print "bar"; print "---"; for (1..10) { eval { print "bar"; next; print "foo"; }; print "Baz"; }
---
$world=~s/war/peace/g

Replies are listed 'Best First'.
Re: Unexpected action at a distance with use warnings FATAL=>'all';
by ruoso (Curate) on Jan 20, 2006 at 17:31 UTC

    Maybe the problem is that you aren't checking exactly what you want to check... I'd suggest the following (full runnable code)

    #!/usr/bin/perl use warnings FATAL => 'all'; use strict; my @cases = 1..19; for my $case ( @cases ) { if (eval { interesting($case) }) { eval { process($case); }; print "$case had processing errors: $@" if $@; } elsif ($@) { print "$case had interesting errors: $@"; } else { print "$case not interesting.".$/; next; } } sub interesting { my $case = shift; die "random failure on interesting" if rand() > 0.7; return rand()>0.5?1:0; } sub process { my $case = shift; print "doing something with $case".$/; die "random failure on process" if rand() > 0.7; }

    Which gave me the following random output...

    1 had interesting errors: random failure on interesting at /tmp/test.p +l line 21. 2 had interesting errors: random failure on interesting at /tmp/test.p +l line 21. doing something with 3 4 had interesting errors: random failure on interesting at /tmp/test.p +l line 21. 5 not interesting. 6 not interesting. doing something with 7 8 not interesting. 9 not interesting. doing something with 10 10 had processing errors: random failure on process at /tmp/test.pl li +ne 28. 11 not interesting. 12 not interesting. 13 not interesting. doing something with 14 14 had processing errors: random failure on process at /tmp/test.pl li +ne 28. 15 not interesting. 16 had interesting errors: random failure on interesting at /tmp/test. +pl line 21. 17 not interesting. doing something with 18 18 had processing errors: random failure on process at /tmp/test.pl li +ne 28. doing something with 19
    daniel
Re: Unexpected action at a distance with use warnings FATAL=>'all';
by jarich (Curate) on Jan 23, 2006 at 02:55 UTC

    next and it's friends are clever little calls in Perl. Did you know you can do this evil thing?

    foreach my $thing (@array) { process($thing); add_to_processed($thing); } sub process { my $thing = shift; next if boring($thing); .... } sub add_to_processed { my $thing = shift; last if too_many($thing); .... }

    Now just imagine that process and add_to_processed are hidden away in another module, or something like that. Your foreach loop looks like it processes each thing in the array and then adds it to the list of processed things. But it doesn't. Some things are skipped, silently, others are left behind when add_to_processed decides it's had enough.

    Call one of these subroutines outside of a loop and watch as sometimes they break, and sometimes they don't! Gotta love it. (Yes, I was given some code a little like this to maintain once....)

    At least eval was telling you about your mislaid next. ;)

    Personally I try to keep eval statements around the smallest scope possible. So I'd be writing:

    for my $case ( @cases ) { my $is_interesting = eval { interesting($case) }; print "$case had errors:$@" if $@; next unless $is_interesting; eval { process($case) }; if ($@) { print "$case had errors:$@"; } }

    or some functional equivalent.

    Your advice is good. Making warnings fatal and other such sweeping changes definately require a code review or at least careful thought.

    Hope you're having fun.

    jarich
Re: Unexpected action at a distance with use warnings FATAL=>'all';
by ysth (Canon) on Feb 09, 2006 at 02:28 UTC

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlmeditation [id://524451]
Approved by Corion
Front-paged by ww
help
Chatterbox?
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (3)
As of 2018-01-21 15:07 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    How did you see in the new year?










    Results (228 votes). Check out past polls.

    Notices?