From: Sean O'Halpin Date: 2005-10-18T04:36:32+09:00 Subject: Re: declaratively caching results of a method On 10/17/05, Brian Buckley wrote: > If I can ask a Ruby 101 question about it... Isn't "cache" in the > module (pasted below in its entirety it is so short) only a local > variable? Why does is retain state? How can one, for example, access > the cache to see the state of the cache? If you hadn't noticed, "meth" is also a local variable. It looks like magic doesn't it? ;) OK - I'll attempt to explain this. > module Memoize > MEMOIZE_VERSION = "1.0.0" > def memoize(name) > meth = method(name) 1. Get a reference to the existing method. This is a ~bit~ like a function pointer. > cache = {} 2. Set up a hash to store memoized results. > (class << self; self; end).class_eval do 3. Common idiom to define a method on the singleton class of the object > define_method(name) do |*args| Here you are defining a method with a do..end block. A block in Ruby is a /closure/ - this means it captures the values of any variables in scope at the time of the block definition (i.e. it captures the /binding/ in effect inside the memoize function). When you call the newly defined method, Ruby will evaluate the block in the context of the captured binding, so it will be able to see any variables visible inside the memoize function. > cache[args] ||= meth.call(*args) 4. If cache[args] has been defined, return it, else set cache[args] to the value of the original method call and return it > end > end > end > end > The key concept to grok is closure. This is a Comp Sci term for a function that carries around the environment it was defined in. (Better plain English definition anyone?) HTH, Regards, Sean