Close and Go BackBack to Viget

Multi-line Memoization

David Eisinger
David Eisinger, Senior Developer, January 05, 2009

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.

blog comments powered by Disqus

We're the Developers

at Viget Labs. We write about web development trends, tips, best practices, industry events, and our projects — all with an emphasis on Ruby on Rails.

Contact Us

Have any questions, comments, ideas, or secrets to share? Let us know.


What color is the sky?

Sorry, you need to have Javascript enabled to use this form. (Don't blame us, blame the spammers!) If you'd like to contact us, please visit our Contact page.