1.6 KiB
title, date, draft, canonical_url
| title | date | draft | canonical_url |
|---|---|---|---|
| Multi-line Memoization | 2009-01-05T00:00:00+00:00 | false | https://www.viget.com/articles/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.