Photo_9_small David Dai 1 post

I just want to point out couple potential problems with the memoization code:

1) Keeping the memory in a closure could potentially lead to memory leaks if you don’t have a way to clear it. Over time it will end up with a huge hash that you have no control of sitting in the memory. Another thing to think about is the input domain of the memorized method. If the input domain is extremely large, you’re probably better off using memcache or drb so memoization bit is not coupled to the process that’s hosting the class.

2) Be careful when memoizing methods with hashes or arrays as your parameters. For instance if you change the expensive_discount_calculation() to the following, your cache will fail because Ruby will generate a different hash key for each of the args arrays:


# ...
   def expensive_discount_calculation(*skus)
    skus.pop if skus.last.is_a? Hash
    puts "Expensive calculation for #{skus.inspect}" 
    skus.inject {|m,n| m + n }
   end
# ...
d = Discounter.new
puts d.discount(1,2,3, :foo => 'bar')  
puts d.discount(1,2,3, :foo => 'bar')  #=>  no cache here.

 
Dave_8_trans_small Dave Thomas Administrator 65 posts

David:

wrt point 1, you’re right—this is a “feature” of all basic caches. In these examples, I really wanted to demonstrate the metaprogramming—caching is just a convenient excuse.

wrt point 2. There’s definitely an issue when passing hashes. Arrays can be more forgiving.

Thanks for the comments

Dave

2 posts, 2 voices