in reply to Re: Creating flexible method accessor
in thread Creating flexible method accessor

Personally I'd stick with the stringy eval. An accessor created that way, would inline $path and $name instead of closing over them. Inlining will result in significantly faster accessors than closing over would.

use Moops; class Cow :rw { has name => (default => 'Ermintrude') }; say Cow->new->name

Replies are listed 'Best First'.
Re^3: Creating flexible method accessor (no benchmark?)
by tye (Sage) on Feb 02, 2014 at 16:54 UTC

    s/significantly/insignificantly/ Plus you'll get proper file and line number information displayed in error messages and even be able to see the relevant source code in the debugger.

    - tye        

      I chose my words very particularly. The difference is not massive, but it is significant - i.e. it's consistently big enough to be detectable. For a very simple rw accessor closing over a single variable (that is, sub { $_[0]{$name} = $_[1] if @_ == 2; $_[0]{$name} }), it's likely to be about 10%.

      For the example which would close over two variables (sub { $_[0]{$path}{$name} = $_[1] if @_ == 2; $_[0]{$path}{$name} }) it's more like 15%.

      File and line number info is easy to add to stringy evals.

      Moose, Moo, etc create accessors this way not just for fun, but because they're measurably faster.

      use strict; use warnings; use Benchmark qw(cmpthese); my $name = 'foo'; my $path = 'foobar'; my $sub1 = sub { $_[0]{$path}{$name} = $_[1] if @_ == 2; $_[0]{$path}{ +$name} }; my $sub2 = eval qq[ sub { \$_[0]{$path}{$name} = \$_[1] if \@_ == 2; \ +$_[0]{$path}{$name} } ] or die($@); my $self = {}; cmpthese -1, { closure => sub { $self->$sub1(0); $self->$sub1( $self->$sub1 + $_ ) for 0..10_000; }, stringy => sub { $self->$sub2(0); $self->$sub2( $self->$sub2 + $_ ) for 0..10_000; }, };
      use Moops; class Cow :rw { has name => (default => 'Ermintrude') }; say Cow->new->name

        Perhaps you need to look up the word "significant". "Can be detected by careful measurement against an isolated subset" doesn't reach the point of "likely to be noticed" which is a minimum requirement for "significant".

        Making your whole program run 10% faster isn't really significant as most people won't notice that something took 0.9 seconds instead of a full second. But making one tiny subroutine 10% faster is going to have much less than 10% impact on the speed of any program. Which is why it is very clearly insignificant. To have significance it has to have a noticeable impact. And impact is only noticed in the run time of real code.

        I note that your benchmark didn't even use the example code being discussed. I bet the benchmark numbers are even more obviously not significant in that case. How insignificant it looks in that case is just a fraction of how insignificant it will be in real code.

        - tye