in reply to Re^2: Memoize::Expire oddity
in thread Memoize::Expire oddity

$ perl -MMemoize -MMemoize::Expire -E " \ sub f { int rand 100 }; \ tie my %cache => 'Memoize::Expire', LIFETIME => 2; \ memoize 'f', LIST_CACHE => 'MERGE', \ SCALAR_CACHE => [ HASH => \%cache ]; \ for (1..10) { say f(); sleep 1 }" 62 62 56 56 39 39 85 85 42

Replies are listed 'Best First'.
Re^4: Memoize::Expire oddity
by Yary (Pilgrim) on Aug 29, 2013 at 15:18 UTC
    Thanks for this example. With a little further modification it demonstrates that Memoize::Expire won't work for functions returning lists:
    perl -MMemoize -MMemoize::Expire -E " \ sub f { ('X',int rand 100) }; \ tie my %cache => 'Memoize::Expire', NUM_USES => 3; \ memoize 'f', LIST_CACHE => 'MERGE', \ SCALAR_CACHE => [ HASH => \%cache ]; \ for (1..6) { say f() }"
    X63
    X
    X
    X67
    X
    X
    
    You should be able to use any tied hash- not only Memoize::Expire but also any of the file-stores- if you first wrap it in something that will freeze/thaw the list beforehand. Example:
    perl -MMemoize -MMemoize::Expire -MSerializeValues -E " \ sub f { ('X',int rand 100) }; \ tie my %subcache => 'Memoize::Expire', NUM_USES => 3; \ tie my %cache => 'SerializeValues', \%subcache; \ memoize 'f', LIST_CACHE => [ HASH => \%cache ], \ SCALAR_CACHE =>'MERGE' ; \ for (1..6) { say f() }"
    X73
    X73
    X2
    X2
    X64
    X64
    
    Below is my SerializeValues wrapper. Note that it seems to call the sub-cache's "FETCH" while it stores, effectively reducing NUM_USES by one. Also since Serialize requires a reference, it has to be in the LIST_CACHE slot, not SCALAR_CACHE.
    #!/usr/bin/env perl package SerializeValues; require Tie::Hash; @ISA = qw(Tie::ExtraHash); use strict; use warnings; use Storable qw[freeze thaw]; sub TIEHASH { my ($class, $child_hash) = @_; return bless [$child_hash], $class; } sub STORE { $_[0][0]{$_[1]}= freeze $_[2] } sub FETCH { thaw $_[0][0]{$_[1]} }
    I'm going to email the author (mjd) and suggest adding a flag to the HASH option to say that the values should be serialized first.

    PS. This module is over a decade old, and within a couple weeks two of us independently run into the same limitation- there's something going around...

      Thanks for this example. With a little further modification it demonstrates that Memoize::Expire won't work for functions returning lists
      Right, which is why when I needed such abilities I wrote my own expiring backend to Memoize. If you want to do the same, start with the INTERFACE section of the Memoize::Expire POD.

      For the record, I also had to implement FIRSTKEY and NEXTKEY methods for things to work correctly.

      Cheers.
        Ah, well... my little example above lets you use any existing tied hash with Memoize in list context, and I'm using it successfully with real code backed by Memoize::Expire in once case and and AnyDBM_File in another. Just a few lines, nothing reimplemented!