Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery
 
PerlMonks  

inline caching a list-generating sub

by ysth (Canon)
on Aug 19, 2005 at 11:28 UTC ( [id://485073]=perlquestion: print w/replies, xml ) Need Help??

ysth has asked for the wisdom of the Perl Monks concerning the following question:

I was reading HOP and it got me thinking about inline caching methods. Assuming the no-false-values constraint is not a problem, there's an easy and efficient way to add caching to a sub that returns a scalar (replace the join as needed):
my %foo_cache; sub foo { $foo_cache{join ",", @_} ||= do { ... rest of sub goes here } }
(If you have it enabled, //= is even better.)

But what about when the function generates a list? Easy enough:

my %foo_cache; sub foo { @{$foo_cache{join ",", @_} ||= [ do { ... rest of sub goes here }]} }
But that changes the result in scalar context if an actual list is returned. The fix is a little expensive:
my %foo_cache; sub foo { return @$_[0..$#$_] for $foo_cache{join ",", @_} ||= [ do { ... rest of sub goes here }] }
Can anybody suggest a less expensive alternative? Pity there's no list keyword.

Replies are listed 'Best First'.
Re: inline caching a list-generating sub
by Roy Johnson (Monsignor) on Aug 19, 2005 at 11:58 UTC
    How about something like
    sub foo { ($foo_cache{...} ||= do { my @result = do { ... rest of sub goes here } sub { @result[0..$#result] }; }; )->(); }
    Wait...if you just want to fix scalar context,
    my %foo_cache; sub foo { my $index = join ",", @_; $foo_cache{$index} ||= do { .... }; wantarray ? @{$foo_cache{$index} : $foo_cache{$index}[-1]; }
    Would there be more to a list keyword than this?
    sub list { wantarray ? @_ : $_[-1]; }

    Caution: Contents may have been coded under pressure.
Re: inline caching a list-generating sub
by Roger (Parson) on Aug 19, 2005 at 12:03 UTC
    Something like this? :-)
    sub foo { $list = $foo_cache{join ',', @_} ||= [ do { ... rest of sub goes here }]; want_array ? @$list : $list; }


      Nicely written, but you're having it return a ref in scalar context, whereas the OP wanted it to behave like a list (which returns the last element). Change the last $list to $list->[-1]

      Caution: Contents may have been coded under pressure.
Re: inline caching a list-generating sub
by eric256 (Parson) on Aug 19, 2005 at 15:27 UTC

    I'm curious what advantage this method provides over Memoize. Perhaps a link to HOP?? I don't know what that is and i wonder if it might answer my question.


    ___________
    Eric Hodges
      Sorry, Higher Order Perl is a book on functional programming in perl, by SchwernDominus, the author of the Memoize module.

      In my experimentation, Memoize has shown quite high overhead. A general solution like that has to impose the cost of a separate sub call, as well as handling all sorts of parameters (e.g. differentiating between undef and "") and caching separately for scalar/list/void context.

      In most cases I've run into, the simple inline scalar caching is sufficient and not too burdensome to insert. Throwing list context into the mix complicates things a lot.

      Update: I really do know the difference between Schwern and Dominus, no idea what bizarre neural connection led me to get that wrong.

      HOP => Higher Order Perl

      It is a great book about how to do 'more' with Perl, especially things like closures & iteration. (And probably more, but I am only ~one-third of the way through the book)

      Hope that helps.

Re: inline caching a list-generating sub (clarity)
by tye (Sage) on Aug 19, 2005 at 21:52 UTC

    Rather than "if an actual list is returned", just say that you want the function to return the last value if used in a scalar context. Then people won't have to try to figure out what lists you consider to be "actual" vs. whatever the other lists are. (:

    What "expense" are you complaining about here? I don't see any big CPU or memory cost being incurred in the last case. Perhaps clarity? If so, just write the code less densely. For example, rather than using a slice just to get the side effect of returning the last item in a scalar context (a justification that would require more guessing when your code is later read), make it clear what you wanted:

    my %foo_cache; sub foo { my $ret = $foo_cache{join",",@_}; ||= [ do { ... } ]; return wantarray ? @$ret : $ret->[-1]; }

    - tye        

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://485073]
Approved by lidden
Front-paged by Old_Gray_Bear
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others avoiding work at the Monastery: (4)
As of 2024-03-29 06:03 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found