in reply to help with a Perl term

eval has two purposes. If given an expression (EXPR), eval will evaluate that expression as a small Perl program. This is generally the form of eval that people term "evil," because it delays execution of the code until runtime. And is thus slow.

Given a block (BLOCK), the block will be compiled at compile-time, rather than run-time (as in the EXPR form). If an error occurs in the expression/block that you're executing, the error message will be in the $@ variable after your eval.

In other words, eval, in combination with die, can be used as an exception mechanism in Perl. For example, you can try to require a module in an eval block, then check $@ (the "exception", in this case) to see if the require has succeeded:

eval { require LWP; }; if ($@) { die "Can't load LWP: $@"; }

Replies are listed 'Best First'.
RE: Re: help with a Perl term
by Shendal (Hermit) on Jun 08, 2000 at 20:03 UTC
    If I understand you correctly, this may solve a problem I've been dealing with when I have scripts designed to work on NT and UNIX.
    Would this work?
    $is_NT = ($ENV{'OS'} eq 'Windows_NT'); if ($is_NT) { eval { use Win32::ODBC; } } else { eval { use DBI; } }
    The problem exists because Win32 doesn't happen to be on my UNIX box. :) Is there another way to conditionally use a module?
      That snippet doesn't do anything if the use() fails. And, what if it is NT but Win32::ODBC isn't installed? What if it is a Win32 system with DBI installed? How about:

      eval { require DBI }; if ($@) { warn "DBI not here.. will keep checking..."; } eval { require Win32::ODBC }; if ($@) { warn "Oh oh"; } ... etc...
      or (ok, this is far fetched):

      my %subs = ('DBI' => \&use_dbi, 'Win32::ODBC' => \&use_odbc, 'Win32::OLE' => \&use_ole ); my @mods = ('DBI', 'Win32::ODBC', 'Win32::OLE'); for (@mods) { eval { require $_ }; if ($@) { warn "No $_ here"; }else{ $subs{$_}->(); last; } }

      Cheers,
      KM

      Shendal, this is totally off the eval topic, but why not just stick with one flavor? I've used DBI on Win32 and UNIX, with great results (even porting from one to the other was great). Is there any specific reason why you would want to use Win32::ODBC instead of DBI? You'll have to change the connect string that creates the database handler anyway.

      Just my R$0.02.

      #!/home/bbq/bin/perl
      # Trust no1!
        Using DBI was just an example. I had a script that used Win32::ODBC. I ported it over to UNIX because I wanted to add support for Oracle, not just Access databases. It was nice to add the functionality without breaking the old stuff -- or having to rewrite it.
        There are times where it would be nice to either use or not use, was my point. For example, using a package if it exists, exiting more gracefully if not. It has been an issue with some of my perl scripts (until now).
RE: Re: help with a Perl term
by KM (Priest) on Jun 08, 2000 at 19:20 UTC
    Out of curiosity, why would you eval the require, then die if the eval fails? If the require fails it would die anyways. Something like this makes a little more sense (to me):

    my $bad; BEGIN { eval { require Foo }; if ($@) { $bad = "Foo"; warn "This requires $bad to work. " . "You can get it at ... "; } } sub new { return undef if $bad; ...etc... }

    Cheers,
    KM

      Well... would you believe that it wasn't a very good example? :)

      That said, there are several situations where I might do something like this:

      • When my eval to require the module is wrapped in another eval, where the outer eval is a general exception handler of sorts. In this case, I'd perhaps have an exception handler set up for this particular exception: loading a module failed. So I'd die w/ that particular exception object (using 5.005's (I think) ability to die with an object). I do this often in mod_perl apps... in fact, I probably abuse the technique. :)

      • This is kind of similar to the first example, but oftentimes I'd rather give an explanation of why the module-load failed, rather than just give the standard "can't find in @INC" message. As you did above, in fact.
      What I do wonder is why you're using warn above. If code you're writing absolutely requires a module to work, why wouldn't you want to die? Just wondering.
        I use warn so I get a warning without killing whatever is happening. If you notice, that example is being used as if it were part of a module, and the new() method returns if it's dependant method isn't loaded. This will keep this module from dying when another module/script is trying to use it, while still giving it a warning. For example, we use this technique extensively with the newest version of the Infobot. I have also used it elsewhere. I wouldn't eval a require to just die if it fails, seems redundant.

        Your example would have been better if you showed it in the contect of the first bullet you explain above. :)

        Cheers,
        KM