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

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.
RIP an inspiration; A true Folk's Guy

Replies are listed 'Best First'.
Re^8: Error handling in chained method calls
by stvn (Monsignor) on Oct 25, 2010 at 16:02 UTC
    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.
        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?

        Actually, probably not where I would go with this no. It would get way to messy to have all this advice sprinkled about your various roles and classes. Not every Moose solution, as you often seem to imply, involves sprinkling more sugar and performance penalties on top of the code.

        I would actually have to agree with your original post, if the chained method calls fail it is likely for one of two reasons. First, the objects are designed poorly and aren't returning the right values/throwing the right error conditions. Second, there is a valid error condition and the chaining really should stop.

        I honestly have a hard time thinking of a case where failing in the middle and not throwing an exception of some kind would be useful. The intended body of work would be existing incompletely and that really should be an error.

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

        Sure, executing code always incurs a performance penalty, you of all people should know that ;)

        -stvn
Re^8: Error handling in chained method calls
by LanX (Saint) on Oct 25, 2010 at 11:06 UTC
    > 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.
        > And I also idealized by avoiding any inheritance.

        > > Within-bounds. Not all classes use inheritance.

        Irrelevant ... it depends WHAT EXACTLY is tested, if this test was about the overall efficiency of method caching, a (reasonable) worst case should be assumed. That means a inheritance complexity worse than 99,9% of all real live cases.

        But I tested the lower bound of memoizing methods, no selfmade caching can be faster.

        Cheers Rolf