Slash Boxes
NOTE: use Perl; is on undef hiatus. You can read content, but you can't post it. More info will be forthcoming forthcomingly.

All the Perl that's Practical to Extract and Report

use Perl Log In

Log In

[ Create a new account ]

autarch (914)

  (email not shown publicly)

Journal of autarch (914)

Friday July 08, 2005
08:42 PM

More exception handling fun

[ #25595 ]

A bit of insidious evil spotted by my coworker Chris Dent.

Consider, if you will, this bit of code:

eval "require $module" unless $module->can('new');
die $@ if $@;
return $module->new();

This is a handy way to conditionally load a class. You need to check $@ because if the module fails to load you want to know.

But there's a somewhat subtle bug lurking in there.

If the module has been loaded already, then the eval is never executed. But it always checks $@. This is bad. If earlier you had some code that did something like this:

eval { thing_that_may_die() };
log_error($@) if $@;
return if $@;

Now $@ has a value and since we may not ever call the string eval, then $@ will still be populated with an old exception at the die $@ if $@ line.

The upshot is that you need to be careful with your use of eval and $@. Make sure that checks on $@ are always preceded by an eval.

So our original bit of code can be rewritten as:

unless ( $module->can('new') )
    eval "require $module";
    die $@ if $@;
return $module->new();

The Fine Print: The following comments are owned by whoever posted them. We are not responsible for them in any way.
More | Login | Reply
Loading... please wait.
  • (in your rewritten code) is that $@ is cleared to become the empty string when control leaves the block. So you shouldn't have the pre-existing value trouble later on when testing "if $@".

    At YAPC::NA::2005, Dave Rolsky cautioned that even with the braces around the eval and the test, you can get into trouble if a later test is "if defined($@)" ... because $@ will have been defined but contain the empty string after leaving an earlier block in which it was used. So he said to use "if length($@)" rather than

  • When an eval fails to compile the code or the code dies, the eval always returns undef. You can use this to shorten many such snippets:

    eval "require $module; 1" or die $@ if not $module->can( 'new' );

    In fact the 1 is actually redundant here, as require always returns a true value itself if it succeeds. To be precise, it returns the value of the last expression in the file, which, as everyone knows, must be true. But neither fact is, to my knowledge, documented.