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

I was looking through some code and I kept coming across the term eval. I read about it in perlfunc:eval but had difficulty understanding what they meant. Could somebody clarify to me what is exactly does? Because at this point, eval is more evil than anything else to me.

-- zdog (Zenon Zabinski)

Replies are listed 'Best First'.
Re: help with a Perl term
by btrott (Parson) on Jun 08, 2000 at 06:52 UTC
    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: $@"; }
      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!
      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.
(jcwren) Re: help with a Perl term
by jcwren (Prior) on Jun 08, 2000 at 17:00 UTC
    'eval' is an extremely powerful and dangerous construct, used in the wrong hands. One of the coolest things about it is that it can make an application (or Perl iteself) extensible, similiar to Forth.

    Imagine a situation where you have a graphical calculator written in Perl. It has four basic functions: add, subtract, divide, multiply. You have a few extra buttons that users can assign functions to. By allowing them to enter an expression, you can create functions that previously didn't exist. You capture the user's function to a string, then 'eval' the string when it's time to use that key in a an expression. You've now extended the function of the calculator.

    It's somewhat slow, since the 'eval' is done at run time instead of compile time, but it can be a neat way to implement otherwise difficult things. Of course, the peril should be obvious. You allow a user to enter something like`rm -rf /`eval that, and they've wiped the hard drive. Any input from users that's fed through 'eval' has to be fully qualified.

    In Forth, you can do something that's even more powerful. The words you create become part of the language itself. You can create new words at compile time, or during run time. You think Perl obfusication can be hairy, try seeing some Forth that produces Forth code, compiles itself, runs itself, and then reproduces itself.

    --Chris
Re: help with a Perl term
by BigJoe (Curate) on Jun 08, 2000 at 06:59 UTC
    eval runs a command or a set of commands. You can test data for its validity through this command.
    eval "$val= ; "; if ( $@ eq "") { print "this is valid"; } else { print "$@ is invalid"; }
    It is a way to trap possible error conditions during run time.
Re: help with a Perl term
by swiftone (Curate) on Jun 08, 2000 at 18:32 UTC
    eval is a beautiful option is used correctly. Uses include:
    • Checking for die conditions without die-ing
    • Giving great user flexibility to specify options in config files. For example, I'm working with a program that has data files that are in essence miniature programs. The datafiles are loaded during run, and each mini-program will need to be executed many times. My solution? I translate the programs into perl when the file is loaded, and eval() them when I need to.
    If you going to use eval with any user-specified data, it is a good idea to turn on taint-checking. See perlman:perlrun for -T, and perlman:perlsec for security concerns in perl.