There should be no difference in runtime performance if the resulting code is the same in both cases. This is usually not possible, however, unless you use string eval
to create your subroutines. For example, the code you provided:
... = sub { $_[0]->{$a} };
will be ever-so-slightly slower than the code you would have written manually:
sub foo { $_[0]->{'foo'} }
simply because the former has to get the value of the variable $a before using it as a key to the hash, whereas the later uses a constant as its hash key. Also, as an aside, shift
usually tends to be faster than $_[0]
. Here's some benchmark code:
use Benchmark qw(cmpthese);
package Foo;
sub manual_shift { shift->{'foo'} }
sub manual_index { $_[0]->{'foo'} }
my $attr = 'foo';
*dynamic_shift = sub { shift->{$attr} };
*dynamic_index = sub { $_[0]->{$attr} };
package main;
my $o = bless { foo => 123 }, 'Foo';
cmpthese(-2, {
manual_shift => sub { my $a = $o->manual_shift },
manual_index => sub { my $a = $o->manual_index },
dynamic_shift => sub { my $a = $o->dynamic_shift },
dynamic_index => sub { my $a = $o->dynamic_index },
});
and the results on my system:
Rate dynamic_index manual_index dynamic_shift manual_shift
dynamic_index 1799024/s -- -3% -4% -7%
manual_index 1853616/s 3% -- -1% -4%
dynamic_shift 1873183/s 4% 1% -- -3%
manual_shift 1937019/s 8% 4% 3% --
They're so close that differences may get lost in the noise, but over many trials I think you'll see that the "manual shift" variant is the fastest. But as with all microbenchmarks like this, you have to test your exact scenario on your hardware and your version of perl to be sure of anything.
And here's string eval thrown into the mix.
eval "sub eval_index { \$_[0]->{'$attr'} }";
eval "sub eval_shift { shift->{'$attr'} }";
It should be exactly the same as the "manual" variants, plus or minus the statistical noise. My results:
Rate dynamic_index manual_index dynamic_shift manual_shift eval_shift eval_index
dynamic_index 1820444/s -- -1% -2% -3% -4% -5%
manual_index 1835005/s 1% -- -1% -2% -3% -4%
dynamic_shift 1858131/s 2% 1% -- -1% -2% -3%
manual_shift 1876708/s 3% 2% 1% -- -1% -2%
eval_shift 1894132/s 4% 3% 2% 1% -- -1%
eval_index 1914060/s 5% 4% 3% 2% 1% --
Again, these are all so close that you'd have to take great pains and perform many trials to sort out the signal from the noise. But the difference between using a constant as a hash key and using a variable (whose value must first be retrieved) as a hash key should show through. (The shift
optimization is a separate issue and is more likely to change one way or the other in past or future versions of perl.)