Some Practical Uses of eval

By: Kurt Starsinic

People frequently ask me questions about eval. What they often want to know is purely practical -- ``How do I do X?'' or ``What does this code do?'' or ``Why doesn't this code work?'' So if you're interested in theory, don't read past the end of this paragraph. Pick up the Camel book, read the on-line Perl documentation, or read a good book on programming concepts. What follows is meant to be used first and studied second.

Deferring errors

Suppose that you've written a tremendously useful Perl program that optionally sends email notifications. You don't want to re-invent the wheel, so you use the excellent Mail::Send module from CPAN. If you put
    require Mail::Send;
at the top of your program, and the user doesn't have Mail::Send installed, then the program will quit immediately, even if the user isn't intending to make use of the email notification feature. A better method might be to put the following in your program _at the point where you're about to deliver email:_

    eval { require Mail::Send } or die <<EOF;
To send email, you must first install Mail::Send.
Mail::Send is available from CPAN; see
http://www.perl.com/CPAN/modules/00modlist.long.html
EOF

Making fatal errors more informative

Perhaps you've written a program that unconditionally requires Mail::Send. You still may want to use eval to make your program more friendly; instead of beginning your program with
    require Mail::Send;
which will output the following when Mail::Send isn't available

Can't locate Mail/Send.pm in @INC (@INC contains: /usr/local/lib/perl5/5.00503/i486-linux-thread /usr/local/lib/perl5/5.00503 /usr/local/lib/perl5/site_perl/5.005/i486-linux-thread /usr/local/lib/perl5/site_perl/5.005 .). BEGIN failed--compilation aborted.

try using this:
    eval { require Mail::Send } or die <<EOF;
This program requires the Mail::Send module, available from CPAN.
EOF

Managing Portability Issues

What if you want to write a portable Perl program, but you don't have access to every possible platform it should run on? If you can identify the parts of your program that depend on features that are OS-dependent, you can enclose them in eval { } and handle errors as they come
    eval { umask 0666 } or print "Notice: cannot set umask on this platform.\n";

    eval {
        select(undef, undef, undef, 1);
        print "Sleeping exactly 1 second.\n";
    } or do {
        sleep(1);
        print "Sleeping _about_ one second.\n";
    }

Working With Dynamic Objects

If you're writing code for a complex object-oriented application, and you've got an object, but you don't know what class it belongs to, you may want to call a particular method on that object if and only if you can:
    eval {
        $this->print_to_screen;
    } or print(Dumper($this), "\n");

Handling All Errors in a Block

You may write a block of code that could fail at any point, but you don't care where it fails:
    eval {
        $x1 = (-$b + sqrt(($b * $b) - (4 * $a * $c))) / 2 * $a;
        $x2 = (-$b - sqrt(($b * $b) - (4 * $a * $c))) / 2 * $a;
        $atan1 = atan2($x1, $y);
        $atan2 = atan2($x2, $y);
    } or do {
        print "Bad math:  undefined results in calculation.\n";
        exit;
    }