DIY method memoization in Ruby
I recently needed to have methods memoized in a Ruby class. The standard way to
do this is to use an instance variable and the ||=
operator:
class Foo
def bar
@bar ||= some_expensive_call
end
end
But I didn’t want to pollute my class like this, so I ended up rolling my own module with some metaprogramming to provide a nice DSL instead:
module Memoizable
def memoize(method_name)
original_method_name = "__original_#{method_name}"
alias_method(original_method_name, method_name)
instance_variable_name = "@#{method_name}"
define_method method_name do
if !instance_variable_defined?(instance_variable_name)
instance_variable_set(
instance_variable_name,
send(original_method_name)
)
end
instance_variable_get(instance_variable_name)
end
end
end
What the method does:
- Line 5: Back up the original method before overwriting it with the memoized version
- Line 9: Overwrite method with the memoized version
- Line 10: If it’s never been called before
- Lines 11-14: Call it and memoize the result
- Line 17: Return the memoized result
Using it is very easy:
class Foo
extend Memoizable
def bar
some_expensive_call
end
memoize :bar
end
And since def bar
returns :bar
, you can even do this:
class Foo
extend Memoizable
memoize def bar
some_expensive_call
end
end
That’s it!