Using Eval for Efficiency

Here are some examples where run-time evaluation can greatly speed up execution.

A Fast Multipattern grep

Consider a grep-like Perl script that can search for any number of patterns and print out only those lines that match all the given patterns (the order of the patterns being unimportant). You might structure the code like this:

while ($s = <>) {
    $all_matched = 1;     # start by assuming all patterns match $s
    foreach $pat (@patterns) {
       if ($s !~ /$pat/) {
            $all_matched = 0; # No, our assumption was wrong
            last;
        }
    }
    print $s if $all_matched;
}

The problem with this code is that the regular expression (/$pat/) is compiled afresh for every line and for every pattern. That is, if you have, say, 10,000 lines in the text to be searched, and three patterns to search for, a.*b, [0-9], and [^def], the patterns will be compiled 30,000 times. The /o flag, which tells Perl to compile the regular expression, cannot be used here because $pat can vary as the program executes.

The fastest approach would be to hardcode the patterns as shown next. Unfortunately, it is also the least reusable approach.

while ($s = <> ) {
    if (  ($s =~ /a.*b/) &&
          ($s =~ /[0-9]$/) &&
          ($s =~ /[^def]/)) {
        print $s;
    }
}

The good news is that it is possible to get this level of efficiency without losing generality. The idea is to hand-craft the “hard-wired” code above at run-time and then to eval it.

The strings constituting the code to be generated are shown in bold in Example 5.2.

Example 5-2. Compiling ...

Get Advanced Perl Programming now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.