# Dynamic programming

**URL:** <https://www.ruby-forum.com/t/dynamic-programming/154654>\
**Category:** Ruby\
**Created:** [December 2, 2008, 5:32pm UTC](https://www.ruby-forum.com/t/dynamic-programming/154654 "2008-12-02T17:32:39Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![limatsao](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/e9a140/32.png) [@limatsao](https://www.ruby-forum.com/u/limatsao)\
**Post date:** [December 2, 2008, 5:32pm UTC](https://www.ruby-forum.com/t/dynamic-programming/154654/1 "2008-12-02T17:32:39Z")

</div>

# I have a class Adam

# I want to modify the method(“m\_a”) so that it will return the cached

result

# If no cached result is available, then return the original result

# I want to create a class method(AKA: macro) to make it DRY

# 

# So far, I have issues like

# 1) dynmically define class variable

# 2) failed to include a module inside a method of a class

# 

# Any suggestion or comments will be appreciated

# 

class Adam  
def self.m\_a  
[“Adam#m\_a”]  
end  
end

class CachedAdam  
caching\_method :adam, :m\_a

def self.caching\_method  
# this method should do something to make the following codes  
end  
end

## CachedAdam#caching\_method should make and load the following codes

# 

# module AdamWithCache

# def m\_a\_with\_cache

# CachedAdam.get\_cached\_m\_a || m\_a\_without\_cache

# end

# def self.include(base)

# base.alias\_method\_chain :m\_a, :cache

# end

# end

# Adam.class\_eval{ include AdamWithCache }

# 

# class CachedAdam

# def self.get\_cached\_m\_a( adam\_id )

# @@cache && @@cache[adam\_id]

# end

# 

# def self.set\_cached\_m\_a(hash\_list)

# hash\_list.each do |k,v|

# @@cache ||={} # failed, any suggestion?

# @@cache[k] = v

# end

# end

# end

---

<div class="post-metadata">

**Author:** ![limatsao](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/e9a140/32.png) [@limatsao](https://www.ruby-forum.com/u/limatsao)\
**Post date:** [December 2, 2008, 10:16pm UTC](https://www.ruby-forum.com/t/dynamic-programming/154654/2 "2008-12-02T22:16:41Z")

</div>

Frank Tao wrote:

> # I have a class Adam
> 
> # I want to modify the method(“m\_a”) so that it will return the cached
> 
> result
> 
> # If no cached result is available, then return the original result
> 
> # I want to create a class method(AKA: macro) to make it DRY

You might want to look at the ‘memoize’ method in ActiveRecord trunk.

> # So far, I have issues like
> 
> # 1) dynmically define class variable

I suggest: don’t use a class variable 🙂 An instance variable of the  
class would be fine. But personally I wouldn’t keep the memoized values  
in the class; I’d keep them in the instances themselves.

> # 2) failed to include a module inside a method of a class

Look at Module.included for this, as shown below.

There are probably cleaner and/or more efficient ways than the  
following, but it demonstrates the principle.

module Cache  
def self.included(base)  
base.extend ClassMethods  
end

```
module ClassMethods
  def caching_method(m)
    name = "orig_#{m}"
    var = "@__#{m}"
    alias_method name, m
    define_method(m) { |*args|
      return instance_variable_get(var) if 

```

instance\_variable\_defined?(var)  
instance\_variable\_set(var, send(name,\*args))  
}  
end  
end  
end

class Adam  
include Cache  
def foo  
rand(100)  
end  
caching\_method :foo  
end

a = Adam.new  
p a.foo  
p a.foo  
p a.foo

Beware of what you really want here though. If foo takes arguments, do  
you want foo(1) and foo(2) to be able to return different values? Do you  
want them both to be cached? If so, I leave that as an exercise for you.

---

<div class="post-metadata">

**Author:** ![limatsao](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/e9a140/32.png) [@limatsao](https://www.ruby-forum.com/u/limatsao)\
**Post date:** [December 3, 2008, 5:10pm UTC](https://www.ruby-forum.com/t/dynamic-programming/154654/3 "2008-12-03T17:10:52Z")

</div>

Brian C. wrote:

> > # 1) dynmically define class variable
> 
> I suggest: don’t use a class variable 🙂 An instance variable of the  
> class would be fine. But personally I wouldn’t keep the memoized values  
> in the class; I’d keep them in the instances themselves.

I suggest: don’t make blanket statements like that 😉  
That depends on what he wants the cache to accomplish. If the cache  
should cache across all instances of Adam, a class variable is  
_exactly_ what he wants. If it should only cache for the specific  
instance of Adam an instance variable is what he wants.  
If there will be many instances of Adam, and if Adam can peform  
operations that invalidate cache then a global cache is so much easier  
to handle than one distributed over all instances of Adam…since two  
instances of adam may have the same item in their caches, and if  
instance one invalidates… how do you find/invalidate the item in  
instance 2?

RF

---

<div class="post-metadata">

**Author:** ![limatsao](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/e9a140/32.png) [@limatsao](https://www.ruby-forum.com/u/limatsao)\
**Post date:** [December 3, 2008, 11:09pm UTC](https://www.ruby-forum.com/t/dynamic-programming/154654/4 "2008-12-03T23:09:21Z")

</div>

On Wed, Dec 3, 2008 at 5:04 PM, Ron F. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> > You might want to look at the ‘memoize’ method in ActiveRecord trunk.
> > 
> > > # So far, I have issues like
> > > 
> > > # 1) dynmically define class variable
> > 
> > I suggest: don’t use a class variable 🙂 An instance variable of the  
> > class would be fine. But personally I wouldn’t keep the memoized values in  
> > the class; I’d keep them in the instances themselves.
> 
> I suggest: don’t make blanket statements like that 😉  
> Correct, this should be thoroughly explained, well I will try 😉  
> That depends on what he wants the cache to accomplish. If the cache should  
> cache across all instances of Adam, a class variable is _exactly_ what he  
> wants. If it should only cache for the specific instance of Adam an  
> instance variable is what he wants.  
> This might indeed be what he wants, but if it is he should be aware of  
> the implications that it has. It is against one of the most valued  
> principles of OO design, a class shall nothing know about its  
> subclasses (1). Now I agree that occasionally this principle shall be  
> violated for good reason. But I have not yet seen a use case for class  
> variables and IIRC not many have on this list. That is why by  
> instinct, and instinct can be wrong of course, many of us warn against  
> class variables, and sometimes without thorough explications.  
> If there will be many instances of Adam, and if Adam can peform operations  
> that invalidate cache then a global cache is so much easier to handle than  
> one distributed over all instances of Adam…since two instances of adam may  
> have the same item in their caches, and if instance one invalidates… how do  
> you find/invalidate the item in instance 2?  
> And how would that be solved by class variables if I may ask?

(1) this is not necessarily easy to see, but assume this code and  
please forgive me for shouting 😉  
class Supa  
@@supa = :super  
def self.supa; @@supa end  
end

p Supa.supa

class Dupa \< Supa  
@@supa = :duper  
def self.supa; @@supa end  
end

p Dupa.supa  
p Supa.supa ### AND THAT REALLY HURTS

## Cheers Robert

Ne baisse jamais la tête, tu ne verrais plus les étoiles.

Robert D. 😉

---

<div class="post-metadata">

**Author:** ![limatsao](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/e9a140/32.png) [@limatsao](https://www.ruby-forum.com/u/limatsao)\
**Post date:** [December 3, 2008, 9:05pm UTC](https://www.ruby-forum.com/t/dynamic-programming/154654/5 "2008-12-03T21:05:02Z")

</div>

Frank Tao wrote:

> # I have a class Adam
> 
> # I want to modify the method(“m\_a”) so that it will return the cached
> 
> result
> 
> # If no cached result is available, then return the original result
> 
> # I want to create a class method(AKA: macro) to make it DRY
> 
> # 
> 
> # So far, I have issues like
> 
> # 1) dynmically define class variable
> 
> # 2) failed to include a module inside a method of a class
> 
> # 
> 
> # Any suggestion or comments will be appreciated
> 
> # 
> 
> class Adam  
> def self.m\_a  
> [“Adam#m\_a”]  
> end  
> end
> 
> class CachedAdam  
> caching\_method :adam, :m\_a
> 
> def self.caching\_method  
> # this method should do something to make the following codes  
> end  
> end
> 
> ## CachedAdam#caching\_method should make and load the following codes
> 
> # 
> 
> # module AdamWithCache
> 
> # def m\_a\_with\_cache
> 
> # CachedAdam.get\_cached\_m\_a || m\_a\_without\_cache
> 
> # end
> 
> # def self.include(base)
> 
> # base.alias\_method\_chain :m\_a, :cache
> 
> # end
> 
> # end
> 
> # Adam.class\_eval{ include AdamWithCache }
> 
> # 
> 
> # class CachedAdam
> 
> # def self.get\_cached\_m\_a( adam\_id )
> 
> # @@cache && @@cache[adam\_id]
> 
> # end
> 
> # 
> 
> # def self.set\_cached\_m\_a(hash\_list)
> 
> # hash\_list.each do |k,v|
> 
> # @@cache ||={} # failed, any suggestion?
> 
> # @@cache[k] = v
> 
> # end
> 
> # end
> 
> # end

THANKS FOR YOUR HELPFUL RESPONSE. I FOUND THAT MY ORIGINAL HAD SOME  
MISTAKES AND THEREFORE DID NOT REFLECT EXACTLY WHAT I WANT.  
SO I UPDATE IT AS FOLLOWS:

class Adam  
def m\_a  
“a”  
end  
end

class CachedMethod  
@@cached\_variables = {}

def self.caching\_method(model, method)  
model, method = model.to\_s, method.to\_s  
@@cached\_variables["#{model}\_#{method}\_cache"] = {}

```
(class << self; self; end).instance_eval do
  define_method "set_cached_#{model}_#{method}" do |hash_list|
    hash_list.each do |k,v|
      @@cached_variables["#{model}_#{method}_cache"][k] = v
    end
  end
  define_method "get_cached_#{model}_#{method}" do |model_id|
    @@cached_variables["#{model}_#{method}_cache"] &&
      @@cached_variables["#{model}_#{method}_cache"][model_id]
  end
end

#
# Purpose: create a module and let it be included by Adam class
# NOT WORKING, any suggestion?
self.class_eval <<-EOD
 module AdamWithCache
   def m_a_with_cache
     CachedMethod.get_cached_adam_m_a(self.id) || m_a_without_cache
   end
   def self.include(base)
     base.alias_method_chain :m_a, :cache
   end
 end
 Adam.class_eval{ include AdamWithCache }
EOD

```

end

def self.reset  
@@cached\_variables = {}  
end

self.caching\_method :adam, :m\_a

end

#module AdamWithCache

# def m\_a\_with\_cache

# CachedMethod.get\_cached\_adam\_m\_a(self.id) || m\_a\_without\_cache

# end

# def self.include(base)

# base.alias\_method\_chain :m\_a, :cache

# end

#end  
#Adam.class\_eval{ include AdamWithCache }

# 

#Example usage:  
#=============================================

puts @adam\_1 = Adam.new #==\> assume: @adam.id == 1  
puts @adam\_2 = Adam.new #==\> assume: @adam.id == 2  
puts @adam\_3 = Adam.new #==\> assume: @adam.id == 3  
puts @adam\_1.m\_a #==\> “a”  
puts @adam\_2.m\_a #==\> “a”  
puts @adam\_3.m\_a #==\> “a”  
puts @adam\_1.id #==\> 1  
puts @adam\_2.id #==\> 2  
puts @adam\_3.id #==\> 3

hash\_list = {@adam\_1.id =\> “b”, @adam\_2.id =\> “c”}  
CachedMethod.set\_cached\_adam\_m\_a(hash\_list)  
puts CachedMethod.get\_cached\_adam\_m\_a(@adam\_1.id) #==\> “b”  
puts @adam\_1.m\_a #==\> “b” !!! DID NOT OUTPUT AS I EXPECTED  
puts @adam\_2.m\_a #==\> “c” !!! DIDO  
puts @adam\_3.m\_a #==\> “a” !!! DIDO

CachedMethod.reset  
puts @adam\_1.m\_a #==\> “a”  
puts @adam\_2.m\_a #==\> “a”  
puts @adam\_3.m\_a #==\> “a”

---

<div class="post-metadata">

**Author:** ![limatsao](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/e9a140/32.png) [@limatsao](https://www.ruby-forum.com/u/limatsao)\
**Post date:** [December 4, 2008, 3:55pm UTC](https://www.ruby-forum.com/t/dynamic-programming/154654/6 "2008-12-04T15:55:58Z")

</div>

Brian C. wrote:

> Frank Tao wrote:
> 
> > # I have a class Adam
> > 
> > # I want to modify the method(“m\_a”) so that it will return the cached
> > 
> > result
> > 
> > # If no cached result is available, then return the original result
> > 
> > # I want to create a class method(AKA: macro) to make it DRY
> 
> You might want to look at the ‘memoize’ method in ActiveRecord trunk.

‘memoize’? Do you mean by the one in Rails 2.2 under  
ActiveSupport::Memoizable ?

I also found Rails.cache or RAILS\_CACHE in Rails 2.1 very helpful.
