in reply to Re^5: Error handling in chained method calls
in thread Error handling in chained method calls

Wow, I'm impressed.

An idealized benchmark shows only a 25% gain by memoizing, so I agree, it doesn't worth it.

Rate classic memoized classic 75415/s -- -19% memoized 93110/s 23% --
use strict; my $obj={}; bless $obj,"Class"; sub classic { $obj->meth0->meth1->meth2->meth3->meth4->meth5->meth6->meth7->meth8- +>meth9; } my $ref0=$obj->can("meth0"); my $ref1=$obj->can("meth1"); my $ref2=$obj->can("meth2"); my $ref3=$obj->can("meth3"); my $ref4=$obj->can("meth4"); my $ref5=$obj->can("meth5"); my $ref6=$obj->can("meth6"); my $ref7=$obj->can("meth7"); my $ref8=$obj->can("meth8"); my $ref9=$obj->can("meth9"); sub memoized { $obj->$ref0->$ref1->$ref2->$ref3->$ref4->$ref5->$ref6->$ref7->$ref8- +>$ref9; } use Benchmark qw/cmpthese/; cmpthese(1E6, { classic => \&classic, memoized => \&memoized, }); package Class; sub meth0 { $_[0] } sub meth1 { $_[0] } sub meth2 { $_[0] } sub meth3 { $_[0] } sub meth4 { $_[0] } sub meth5 { $_[0] } sub meth6 { $_[0] } sub meth7 { $_[0] } sub meth8 { $_[0] } sub meth9 { $_[0] }

Cheers Rolf

Replies are listed 'Best First'.
Re^7: Error handling in chained method calls
by BrowserUk (Patriarch) on Oct 25, 2010 at 03:08 UTC
    An idealized benchmark

    Hm. I'm not sure that "idealized" really described your benchmark. And neither does "memoized"--more like "hard-coded".

    Are you really suggesting that every user of every class should build a lexical cache of every method for each class they use, in each package they use it, and then hard-code all their method calls in terms of that lexical cache?

    I've removed your hard-coded version as unrealistic, and replaced with paranoid() reflecting the OPs suggested methodology. I've also added a realistically memoised version of that suggestion to show that it doesn't help:

    use strict; my $obj = Class->new; sub classic { $obj->meth0->meth1->meth2->meth3->meth4->meth5->meth6->meth7->meth8- +>meth9; } sub paranoid { $obj and ref $obj and my $ref0 = $obj->can('meth0'); $obj and ref $obj and my $ref1 = $obj->can('meth1'); $obj and ref $obj and my $ref2 = $obj->can('meth2'); $obj and ref $obj and my $ref3 = $obj->can('meth3'); $obj and ref $obj and my $ref4 = $obj->can('meth4'); $obj and ref $obj and my $ref5 = $obj->can('meth5'); $obj and ref $obj and my $ref6 = $obj->can('meth6'); $obj and ref $obj and my $ref7 = $obj->can('meth7'); $obj and ref $obj and my $ref8 = $obj->can('meth8'); $obj and ref $obj and my $ref9 = $obj->can('meth9'); $obj->$ref0->$ref1->$ref2->$ref3->$ref4->$ref5->$ref6->$ref7->$ref +8->$ref9; } my %memo; sub memoized { $obj and ref $obj and my $ref0 = $memo{ meth0 } || $obj->can('meth +0'); $obj and ref $obj and my $ref1 = $memo{ meth1 } || $obj->can('meth +1'); $obj and ref $obj and my $ref2 = $memo{ meth2 } || $obj->can('meth +2'); $obj and ref $obj and my $ref3 = $memo{ meth3 } || $obj->can('meth +3'); $obj and ref $obj and my $ref4 = $memo{ meth4 } || $obj->can('meth +4'); $obj and ref $obj and my $ref5 = $memo{ meth5 } || $obj->can('meth +5'); $obj and ref $obj and my $ref6 = $memo{ meth6 } || $obj->can('meth +6'); $obj and ref $obj and my $ref7 = $memo{ meth7 } || $obj->can('meth +7'); $obj and ref $obj and my $ref8 = $memo{ meth8 } || $obj->can('meth +8'); $obj and ref $obj and my $ref9 = $memo{ meth9 } || $obj->can('meth +9'); $obj->$ref0->$ref1->$ref2->$ref3->$ref4->$ref5->$ref6->$ref7->$ref +8->$ref9; } use Benchmark qw/cmpthese/; cmpthese(1E6, { classic => \&classic, paranoid => \&paranoid, memoized => \&memoized, }); package Class; sub new { bless {}, $_[0] } sub meth0 { $_[0] } sub meth1 { $_[0] } sub meth2 { $_[0] } sub meth3 { $_[0] } sub meth4 { $_[0] } sub meth5 { $_[0] } sub meth6 { $_[0] } sub meth7 { $_[0] } sub meth8 { $_[0] } sub meth9 { $_[0] } __END__ C:\test>junk Rate memoized paranoid classic memoized 101102/s -- -9% -65% paranoid 111099/s 10% -- -61% classic 286123/s 183% 158% --

    I was tempted to add a Moose example, but that would be just like bear-baiting.


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      I was tempted to add a Moose example, but that would be just like bear-baiting.

      A Moose example wouldn't be any different because you are not hitting upon the places where Moose is slow. A method call in Moose is the same as a method call in a vanilla Perl object, and Moose does not override &can, seems like you are just trolling Moose again. Oh well.

      -stvn
        A method call in Moose is the same as a method call in a vanilla Perl

        Wouldn't the normal response to such a requirement be to use the before or after or around keywords to add pre and/or post conditions to the methods?

        And wouldn't those extra layers have some performance penalty?


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
      > An idealized benchmark

      > >Hm. I'm not sure that "idealized" really described your benchmark. And neither does "memoized"--more like "hard-coded".

      It's called a lower bound approximation.

      And BTW I also idealized by avoiding any inheritance.

      Cheers Rolf

        It's called lower bound approximation.

        In this case, I'd call it out-of-bounds :)

        And I also idealized by avoiding any inheritance.

        Within-bounds. Not all classes use inheritance.


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.