Hello Tony,
I am not sure what the answer is to your question because I cannot run the program with your module definition above. May be you have made more changes in the program below where remember method is called?
Please see my program below with your changes:
module Memoize def remember(method, &block) memory = {} define_method(method) do |*args| return memory[args] if memory.has_key?(args) memory[args] = block.call(*args) end end end class Discounter extend Memoize remember :discount do |*skus| expensive_discount_calculation(*skus) end private def expensive_discount_calculation(*skus) puts "Expensive calculation for #{skus.inspect}" skus.inject {|m,n| m + n } end end d = Discounter.new puts d.discount(1,2,3) puts d.discount(1,2,3) puts d.discount(2,3,4) puts d.discount(2,3,4) d1 = Discounter.new puts d.discount(1,2,3)
I get the following error message:
C:/NBProjects/MetaProgDaveThomas/lib/main.rb:15: undefined method `expensive_discount_calculation’ for Discounter:Class (NoMethodError) from C:/NBProjects/MetaProgDaveThomas/lib/main.rb:6:in `call’ from C:/NBProjects/MetaProgDaveThomas/lib/main.rb:6:in `discount’ from C:/NBProjects/MetaProgDaveThomas/lib/main.rb:28
I am not sure what the answer is but from the error message, but it seems to me that the way you have defined the module the dynamic method discount becomes a class method when the module is extended in the class, and a class method cannot call an instance method expensive_discount_calculation.
Just after I wrote this post, I decided to check if my theory is true and made the following change to the definition/declaration of expensive_discount_calculation method.
def self.expensive_discount_calculation(*skus)
so, you see, the only change that I made is I put a self in front of the method name making it a class method. It ran fine. So the question boils down to what is better for meta-programming defining an instance method dynamically or a class method? At least in Java world when you don’t need to define and isolate state, i.e., instance variables, we prefer to define class methods since they are shared by all instances of the class and means less overhead for the compiler/interpreter, so I tend to think that this is preferable in terms of efficiency if the same logic holds true in Ruby world. But I am not an experienced Ruby and/or Rails programmer so I can easily be wrong.
I hope you don’t mind me joining the thread since these are precisely the kind of questions that I am struggling with at this point. It would be great to hear what David has to say.
Regards,
Bharat