davideisinger.com

My personal website
Log | Files | Refs | README

index.md (1657B)


      1 ---
      2 title: "Multi-line Memoization"
      3 date: 2009-01-05T00:00:00+00:00
      4 draft: false
      5 canonical_url: https://www.viget.com/articles/multi-line-memoization/
      6 ---
      7 
      8 Here's a quick tip that came out of a code review we did last week. One
      9 easy way to add caching to your Ruby app is to
     10 [memoize](https://en.wikipedia.org/wiki/Memoization) the results of
     11 computationally expensive methods:
     12 
     13 ```ruby
     14 def foo
     15   @foo ||= expensive_method
     16 end
     17 ```
     18 
     19 The first time the method is called, `@foo` will be `nil`, so
     20 `expensive_method` will be called and its result stored in `@foo`. On
     21 subsequent calls, `@foo` will have a value, so the call to
     22 `expensive_method` will be bypassed. This works well for one-liners, but
     23 what if our method requires multiple lines to determine its result?
     24 
     25 ```ruby
     26 def foo
     27   arg1 = expensive_method_1
     28   arg2 = expensive_method_2
     29   expensive_method_3(arg1, arg2)
     30 end
     31 ```
     32 
     33 A first attempt at memoization yields this:
     34 
     35 ```ruby
     36 def foo
     37   unless @foo
     38     arg1 = expensive_method_1
     39     arg2 = expensive_method_2
     40     @foo = expensive_method_3(arg1, arg2)
     41   end
     42 
     43   @foo
     44 end
     45 ```
     46 
     47 To me, using `@foo` three times obscures the intent of the method. Let's
     48 do this instead:
     49 
     50 ```ruby
     51 def foo
     52   @foo ||= begin
     53     arg1 = expensive_method_1
     54     arg2 = expensive_method_2
     55     expensive_method_3(arg1, arg2)
     56   end
     57 end
     58 ```
     59 
     60 This clarifies the role of `@foo` and reduces LOC. Of course, if you use
     61 the Rails built-in [`memoize`
     62 method](http://ryandaigle.com/articles/2008/7/16/what-s-new-in-edge-rails-memoization),
     63 you can avoid accessing these instance variables entirely, but this
     64 technique has utility in situations where requiring ActiveSupport would
     65 be overkill.