Multi-line Memoization
Here’s a quick tip that came out of a code review we did last week. One easy way to add caching to your Ruby app is to memoize the results of computationally expensive methods:
def foo @foo ||= expensive_method end
The first time the method is called, @foo
will be nil
, so expensive_method
will be called and its result stored in @foo
. On subsequent calls, @foo
will have a value, so the call to expensive_method
will be bypassed. This works well for one-liners, but what if our method requires multiple lines to determine its result?
def foo arg1 = expensive_method_1 arg2 = expensive_method_2 expensive_method_3(arg1, arg2) end
A first attempt at memoization yields this:
def foo unless @foo arg1 = expensive_method_1 arg2 = expensive_method_2 @foo = expensive_method_3(arg1, arg2) end @foo end
To me, using @foo
three times obscures the intent of the method. Let’s do this instead:
def foo @foo ||= begin arg1 = expensive_method_1 arg2 = expensive_method_2 expensive_method_3(arg1, arg2) end end
This clarifies the role of @foo
and reduces LOC. Of course, if you use the Rails built-in memoize
method, you can avoid accessing these instance variables entirely, but this technique has utility in situations where requiring ActiveSupport would be overkill.