Item 54: Know how and when to use eval , require , and do .One of the advantages that Perl shares with certain other interpreted languages is the ability to compile and execute code at run time. The basic mechanism for run-time compilation is the string form of the eval operator, which takes a string argument containing source code. For example:
The contents of the string are compiled and then run in the context of the callerin the current package, with package and local variables (even my variables) available to it. The string is compiled each time the eval is executed. The result of eval is the value of the last expression evaluated inside the eval , similar to the way subroutines work. Should the code fail to compile, or suffer a run-time exception (as from die , divide-by-zero, etc.), execution of the eval -ed code ends and an error message is returned to the calling context in the special variable $@ : Handle exceptions (inefficiently) with string eval .
The exception-handling abilities of eval are very handy. However, if all you need to do is add exception handling to an unchanging hunk of code, you should not be using the string form of eval . You should be using the block form. Exception handling with evalThe block form of eval takes a block as its argument. The block form is used solely for exception handling, because the block is compiled only once, at the same time as the surrounding code: Handle exceptions with block eval (preferred).
The block form of eval turns out to be more useful than the string form. Occasions to use the string form are rare (but see the example later in this Item). Although both forms of eval will catch exceptions, neither will catch signals, panics, or other types of "really fatal" errors. They also cannot "bring you back" from an exec or something similar. You can, however, benefit by adding signal handlers to eval blocks: Use eval with signal handlers.
Incorporating source files at run time with requireAlthough the string form of eval is rarely used, it forms the basis for a very important "file" form of run-time compilation, require . The require directive takes a numeric or string argument. The numeric form of require causes a fatal error if the current version of Perl is not equal to or greater than the numeric argument:
The string version, which is the one more relevant to the current discussion, reads in Perl source code at run time and executes it. In other words, it eval s the contents of a file: Loading and executing source code at run time with require
Unlike eval , require uses the last expression evaluated in the included source file to determine whether the inclusion was successful. If the value is false, the load is deemed unsuccessful and require produces a fatal exception. This is why Perl module and library source files often end in " 1; " on a line by itself. In the good old days of Perl 4, require was the primary mechanism used to support Perl libraries. Library source files would typically define subroutines and (possibly) run some initialization code, much as in the example above. The use directive has largely supplanted require , although use is built on require (see Item 42). Now, what require does is actually a little more sophisticated than reading source code and eval -ing it. (See do , discussed later, for the bare bones version.) First, require only loads a file once. Attempts to require a file more than once are ignored. Second, require searches the module include path for the specified filename. (The include path would ordinarily include the current directory.) See Item 43 for more about the module include path . Finally, if the argument to require is a bareword (an unquoted identifier), require automatically adds the extension .pm ("Perl Module") to the argument and searches for a file by that name . This is part of require 's support for the use directive. Doing things with doWe have seen how eval has two somewhat different meanings (string and block form) and how require also does (Perl version and source file inclusion). We are about to discuss Perl's do operator, and you might wonder whether it too has more than one meaning. Of course it does. The file form of do is similar to require , but has fewer frills. It returns the value of the last statement evaluated in the included file, and it makes no difference whether this value is true or false. Neither does the file form of do presume a .pm suffix in the case of a bareword argument. The file form of do does, however, use the module include path. The file form of do can be useful at times. It is a handy way to load a " configuration file" of data, if the data can be written as Perl source: Loading configuration files with require
It is also useful in combination with Data::Dumper (see Item 37) and other modules that generate Perl code. The other form of do , the block form, has nothing to do with either files or eval , but we might as well cover it here. The block form returns the value of the last statement evaluated in its argument block:
The block form is hacked so that if it is used as the expression argument to a statement modifier, it is always evaluated once before the modifier's condition is tested . This allows you to write do { } while loops in Perl:
Creative uses for string evalThe only occasions in which the string form of eval is really worthwhile is when there is a need to read or generate, then execute, Perl code on the fly. You might, for example, allow a user to type in a function, then compile it so that it could be plotted or analyzed for roots, minima, maxima, or whatever. Hopefully this will be a trusted user who will stick to typing in mathematical functions; otherwise you should check out the Safe module. You can also use string eval to generate boilerplate functions automatically. Here is a slightly contrived example along those lines. The following code automatically generates "get" and "set" functions for Perl objects: Generating class boilerplate with string eval
It might seem that this sort of application absolutely requires the use of string eval , but it doesn't. You can achieve the same effect by using closures (see Item 29), along with assignments to typeglobs to give them globally visible names . Closures are a more difficult mechanism for most programmers to understand, though, and in this case eval is probably the best way to go. For a real module providing this kind of functionality, check out Class::Template . |