On Nov 12, 2005, at 11:18 PM, Ken Williams wrote:
Yeah, I know, but I posted it because I didn't really like the
other solutions; while they use "better" (and more complicated)
techniques, they won't actually solve the OP's problem. The
"pretend you have methods instead of subroutines" solution is just
wishful thinking, and the "dispatch tables" solution seems
overengineered and won't work unless the specific list of allowed
functions (rather than just a naming-scheme pattern or similar) is
known to the dispatcher.
The subroutines have to be known anyway. Unless, of course, you're
going to let the eval() just crash...
James, if you don't want to use an eval, and you need to call
functions by name this way, you can just use a symbolic reference:
&{$subroutine_name}($hashref);
When in doubt, benchmark it:
#!/usr/bin/perl
use strict;
use warnings;
use Benchmark qw(:all);
my %dispatch = (
'a' => \&a,
'b' => \&b,
'c' => \&c,
);
my $hashref = {
'foo' => 1,
'bar' => 2,
'baz' => 3,
};
timethese(100000, {
'Dispatch Table' => sub {
for my $sub_name ('a', 'b', 'c', 'b', 'c', 'a', 'a',
'c', 'b') {
$dispatch{$sub_name}->($hashref);
}
},
'Symref' => sub {
for my $sub_name ('a', 'b', 'c', 'b', 'c', 'a', 'a',
'c', 'b') {
{
no strict 'refs';
&$sub_name($hashref);
}
}
},
'Eval' => sub {
for my $sub_name ('a', 'b', 'c', 'b', 'c', 'a', 'a',
'c', 'b') {
eval "$sub_name(\$hashref)";
}
},
});
sub a {
my ($hr) = @_;
my $foo = "\t" . join(",", keys(%$hr)) . "\n";
}
sub b {
my ($hr) = @_;
my $foo = "\t" . join(",", keys(%$hr)) . "\n";
}
sub c {
my ($hr) = @_;
my $foo = "\t" . join(",", keys(%$hr)) . "\n";
}
The results I get are:
Benchmark: timing 100000 iterations of Dispatch Table, Eval, Symref...
Dispatch Table: 17 wallclock secs (14.77 usr + 0.29 sys = 15.06 CPU)
@ 6640.11/s (n=100000)
Eval: 155 wallclock secs (139.45 usr + 3.23 sys = 142.68 CPU)
@ 700.87/s (n=100000)
Symref: 18 wallclock secs (17.49 usr + 0.35 sys = 17.84 CPU) @
5605.38/s (n=100000)
The Eval results are no surprise - it has to compile the string for
each iteration, which is a huge performance hit.
The symref approach has some overhead too, I suppose because of the
extra scoping block for "no strict", but it's relatively small.
Still, it's enough to make using symrefs a questionable idea.
I have to admit, I'm puzzled about why you'd call the dispatch table
"over engineered". There's a difference in syntax when the sub is
called, but that's trivial. The only substantial difference is the
addition of the dispatch table itself, which isn't exactly a
herculean effort. The result is both the cleanest and fastest of the
three approaches.
sherm--
Cocoa programming in Perl: http://camelbones.sourceforge.net
Hire me! My resume: http://www.dot-app.org