Memoization in Ruby

This tutorial will help you understanding Memoization pattern in Ruby. Memoization is different from Lazy Initialization. Rails had Memoize to support memoization pattern which will be discussed as well.

What is Memoization?

Memoization can be used to initialize a variable and store it with the result of some computation that is expected to give same result if computed again. Then, the variable is used to return result instead of doing the computation again when needed again.

E.g.

def user_score
  @user_score ||= # some complex calculation for user score
end

The method user_score calculates score based on some complex calculation and stores it in the instance variable @user_score. When code/flow needs value of user_score again then if value @user_score is set then it is returned instead of computing again.

Above statement can also be written as,

@user_score = @user_score || # some complex calculation for user score

This is simplified version.

When to use Memoization

  1. When you have complex calculation that is supposed to give same result on multiple calls

  2. When you have database query with same parameters for a instance

e.g.

def user_score
  @user_score ||= User.where(name: 'Sam').first.try(:name)
end

If you need user Sam’s score then you can calculate and store it. When you need again then you can just return it from the instance variable.

  1. When you have a method that is giving same result over multiple calls but you need to call it multiple times

What about nil, false?

Memoization technique discussed above does not work with nil, false values. Let us see why.

@variable ||= false # suppose calculation value is false

which simplifies as

@variable = @variable || false

As @variable had false value it will again go and evaluate for the OR part of condition which will come out false again.

Same will happen in case of nil as well.

Thus, over multiple calls Memoization will not work if value comes out to be nil, or false.

Solution to nil, false scenario for Memoization

def variable
  @variable = false unless instance_variable_defined? :@variable
  @variable
end

This will not perform calculation which returns result false/nil if the @variable value is already defined. Thus, this solution holds the memoization pattern.

Confused with Lazy Initialization?

What is Lazy initialization?

Lazy initialization is delaying intialization of the object/entity until the need of it for first time.

class User
  def initialize
    @user_score = # same complex caluclation for user score
  end
end

This is example of Not Using Lazy Initialization. @user_score is calculation at the construction time.

class User
  def initialize
  end

  def user_score
    @user_score ||= # same complex caluclation for user score
  end
end

This is the example of lazy intialization in above context. This is use of Memoization in combination with Lazy intialization.

Does Rails support Memoization?

Rails had support for Memoize through ActiveSupport::Memoizable. Memoizable is deprecated from Rails.

We will not go in deep understanding Memoize from Rails as it has been deprecated.

Check this commit as to why Memoizable support has been deprecated.

References

Memoization | Lazy Initialization

Feel free to comment if you have any doubts/suggestions.

-->