Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery
 
PerlMonks  

Error Handling Misconception

by Anonymous Monk
on Sep 03, 2003 at 22:04 UTC ( [id://288749]=perlquestion: print w/replies, xml ) Need Help??

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

Hi all,

Warning: I have never used eval to error-handle before. I've been avoiding it for more than a year now. I thought I had seen enough examples to be sure how it worked. Obviously I was wrong.

I have code that both creates and loops over objects. The details of the objects shouldn't matter too much, I think. I normally use this object like so:

my $object = My::Class->new(); while (my $value = $object->next_val() ) { # do cool stuff }

But I am using this object in a CGI, and I thought I had best catch problems gracefully, with some nice error explanation rather than just a 500 error. I wanted to use syntax like:

my $object = My::Class->new(); while (my $value = eval { $object->next_val() } ) { if ($@) { print "Error: $@\n"; next(); } # do cool stuff }

This didn't quite work as I expected, though, and I'm not sure why. This code works just fine if the eval succeeds, but it never gets to my error-handling code, even if the eval fails. I have also tested adding the same error-handling code after my while loop.

So, I seem to have some misconception about how eval should behave: can anybody point it out to me, please?

Replies are listed 'Best First'.
Re: Error Handling Misconception
by bobn (Chaplain) on Sep 03, 2003 at 22:16 UTC

    if the eval fails, it your function probably also returned a false value, which caused your while loop to skip the if ( $@ ) code.

    --Bob Niederman, http://bob-n.com

    All code given here is UNTESTED unless otherwise stated.

      Thanks for the suggestion. That doesn't seem to be it, though: I still get the program dying w/o error if I do just this:

      my $value = eval { $object->next_value() }; if ($@) { print "BLAH!\n"; } print $value, "\n";

      ...and no output to screen.

        works for me:

        my $object = new wierd; my $value = eval { $object->next_value() }; if ($@) { print "BLAH!\n$@\BLAH!\n"; } print $value, "\n"; package wierd; sub new { bless {}, shift} sub next_value { die "badness"; }
        Produces:
        BLAH! badness at ./tstprog.pl line 13. BLAH!

        Are you sure you're in a situation where you can see what's printed? What happens when the routine works and $value is something printable?

        --Bob Niederman, http://bob-n.com

        All code given here is UNTESTED unless otherwise stated.

        Make sure a header goes out to the browser before the die message. If your code dies before it had the chance to print the header, then you will likely get an error. I susally just do this at the beginning of my cgi:
        print "Content-type: text/html\n\n";
        Hope that helps,
        selk

        I feel stupid...

        Are you sure you're in a situation where you can see what's printed? What happens when the routine works and $value is something printable?

        Once I took it out of CGI and put it in a text-file to get the minimum error, it worked. There's a bug somewhere in my CGI that I'll have to track down, but this is working fine now. Thank you muchly.

Re: Error Handling Misconception
by gjb (Vicar) on Sep 03, 2003 at 22:27 UTC

    To catch die's with eval, the eval block must be terminated with a semi-colon.
    So you'd better be off rewriting the while as

    for (;;) { my $value = eval { $object->next_val() }; if ($@) { print "Error: $@\n"; next; } last unless $value; # do something useful... }

    Hope this helps, -gjb-

    Update: Althought chromatic puts it very politely, he's dead right: the semi-colon stuff above was nonsense. Thanks chromatic for making me think twice.
      To catch die's with eval, the eval block must be terminated with a semi-colon.

      Do you have a source for this?

      sub dies { die "That's it!"; } if (eval { dies(); 1 }) { print "No death!\n"; } else { print "Death caught: $@\n"; }
      You probably got that idea about the semi-colon from the Error module which uses sub refs to implement a try/catch syntax. The sub refs do require a semi-colon.
Re: Error Handling Misconception
by line_noise (Sexton) on Sep 04, 2003 at 13:48 UTC
    If you haven't already, you might want to check out CGI::Debug. All you have to do is

    use CGI::Debug;

    and you get all of the CGI vars and evalish errors in a report format displayed inline at the bottom of your page. It saves a lot of time debugging the kind of error handling you're working on.
Re: Error Handling Misconception
by kesterkester (Hermit) on Sep 04, 2003 at 13:04 UTC
    I'm interested in what advice the monks can give on the following form of eval error catching-- I picked it up at work and have been using it for a while, with pretty good success. I use programs that run other programs at work, and this displays which program died when a die happens.
    eval { main () }; print STDERR "# $0: ", $@ and exit 1 if $@; exit 0; sub main { # do everything ... }
    I don't use the try/catch form of eval much, although it does seem to work with the above:
    eval { main () }; print STDERR "# $0: ", $@ and exit 1 if $@; exit 0; sub main { my $val = eval { test_sub () }; print "hi" if $@; } sub test_sub { die "test_sub dies" }
    prints "hi", not "# <programname>: test_sub dies", as I expected. Any advice? Could this lead me to shoot myself in the foot later on? Thanks much.

      Why did you expect it to do anything else? Your inner eval caught the first exception, but instead of propagating it, you discarded it and printed "hi". The outer eval saw no error, becauase the iner eval ignored it.

      This program behaved exactly as expected.

      If you wanted the this to do something else, the followingin (untested) would have been better:

      sub main { my $val = eval { test_sub () }; die "hi" if $@; }

      --Bob Niederman, http://bob-n.com

      All code given here is UNTESTED unless otherwise stated.

Re: Error Handling Misconception
by aquarium (Curate) on Sep 04, 2003 at 13:28 UTC
    if i understand $@ correctly: it contains an error message for the "most recent" statement. in this case it's supposed to be the eval, but instead it's the assignment, which resets $@ to null. so the loop should be
    while (eval { my $value = $object->next_val() }) { # do cool stuff } print "Error: $@\n" if($@);
      According to perlvar,

      $EVAL_ERROR
      $@
      The Perl syntax error message from the last eval() operator. If $@ is the null string, the last eval() parsed and executed correctly (although the operations you invoked may have failed in the normal fashion). (Mnemonic: Where was the syntax error ``at''?)

      Warning messages are not collected in this variable. You can, however, set up a routine to process warnings by setting $SIG{__WARN__} as described below.

      Also see Error Indicators.

Re: Error Handling Misconception
by Roger (Parson) on Sep 05, 2003 at 02:14 UTC
    The while loop would fail if your eval { $object->next_val() } returns undef (or fails), thus it will never get into the error checking code when the evaluation fails. If you switch to a do { eval; check; ... } while loop, then the error handling will be effective.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://288749]
Approved by davido
Front-paged by Enlil
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others wandering the Monastery: (3)
As of 2024-03-29 06:56 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found