Hello Monks,
I was reading through
Effective Perl Programming, and at the end of Item 29, the author describes using closures with
eval to "generate subroutines that have particular regular expressions 'locked in' with the same flexibility (and efficiency!) as if the expressions were specified at compile time." (pg. 114) Here is the sample subroutine that produces closures, along with extra code I added for testing:
#!/usr/local/bin/perl -w
use strict;
use re 'debug';
sub make_grep {
my $pat = shift;
eval 'sub { grep /$pat/o, @_ }';
}
my $foo = make_grep( q/sacked/);
warn 'assigned coderef to $foo';
my @mtchs = $foo->( qw(sacked soccer) );
warn 'called $foo->()';
I added
use re 'debug' so I could see when
$pat gets
compiled, and I found that it doesn't until
$foo->() is called
(the output from the
warn statements appears in red):
assigned coderef to $foo at anon line 11.
Compiling REx `sacked'
size 4 first at 1
1: EXACT <sacked>(4)
4: END(0)
anchored `sacked' at 0 (checking anchored isall) minlen 6
Guessing start of match, REx `sacked' against `sacked'...
Found anchored substr `sacked' at offset 0...
Guessed: match at offset 0
Guessing start of match, REx `sacked' against `soccer'...
Did not find anchored substr `sacked'...
Match rejected by optimizer
called $foo->() at anon line 13.
Freeing REx: `sacked'
Then I started wondering what the difference was between assigning an
eval'ed single-quoted string containing an anonymous sub declaration (as above, that produces a coderef) and assigning a coderef without
eval. So I changed
make_grep above to this:
sub make_grep {
my $pat = shift;
sub { grep /$pat/o, @_ };
}
The rest of the code stayed the same, and here is the output, (warnings in red again):
assigned coderef to $foo at anon line 11.
Compiling REx `sacked'
size 4 first at 1
1: EXACT <sacked>(4)
4: END(0)
anchored `sacked' at 0 (checking anchored isall) minlen 6
Guessing start of match, REx `sacked' against `sacked'...
Found anchored substr `sacked' at offset 0...
Guessed: match at offset 0
Guessing start of match, REx `sacked' against `soccer'...
Did not find anchored substr `sacked'...
Match rejected by optimizer
called $foo->() at anon line 13.
What, if any, are the advantages of either method over the other? I have read many times that string
eval should usually be avoided. In this case, it seems that both methods produce the same subroutine, where the regex will only be compiled the first time the method is invoked. I am confused as to why the author suggest using
eval when it appears that assigning a coderef alone accomplishes the same thing. This topic was touched on in
eval with sub, but I did not find a satisfactory answer in that thread.
Also, does anyone know why the
eval'ed version triggers the "Freeing REx" output while the other version does not? (This occurs with Perl 5.6.0. Perl 5.7.2 (Devel) does not give the message for either version of the program.)
Thanks!
--
sacked