Table of contentsClick link to navigate to the desired location
This content has been automatically translated from Ukrainian.
Memoization — is an optimization technique that involves caching the results of function executions to avoid redundant computations on subsequent calls. This is especially useful for expensive operations (such as database queries, complex calculations, or working with APIs).
Why this name?
The term "memoization" comes from the English word "memo" (note, reminder) and the Latin root "memor-" (to remember). This suggests that the function "remembers" (caches) its results to avoid redundant computations.
The term was first used by Donald Michie, a British scientist in the field of artificial intelligence, back in 1968. He described the technique where computed values are stored for future use.
Why not just "caching"?
Memoization is a specific type of caching.
- Memoization typically caches function results at the instance level of an object or within a single process.
- Caching in general can include storage in databases, files, Redis, and not just in variables.
That is, all memoization is caching, but not all caching is memoization.
How does Memoization work in Ruby?
In Ruby, memoization typically uses the ||= operator (or explicit assignment of the value to a variable) to store the result in a variable and return it on subsequent calls.
class User
attr_reader :name
def initialize(name)
@name = name
end
def formatted_name
@formatted_name ||= name.upcase
end
end
user = User.new("Marty")
puts user.formatted_name # Performs computation and stores the value
puts user.formatted_name # Uses cached value
In this case, @formatted_name ||= name.upcase means:
- If @formatted_name is not yet set (nil or false), it will get the value name.upcase.
- Otherwise, the already stored value is returned.
Note regarding ||=
The ||= operator works correctly if the value can be nil or false, but if the expected value can be false, then such memoization will not work. For example:
@result ||= false
If @result is false, the expression will compute again.
For reliable memoization, explicit assignment can be used:
@result = some_expensive_operation if @result.nil?
How does Memoization work in Rails?
In Ruby on Rails, memoization is used to optimize database queries and other costly operations. Example of memoization in a model:
class User < ApplicationRecord
def expensive_query
@expensive_query ||= some_heavy_calculation
end
private
def some_heavy_calculation
sleep(2) # Simulating a heavy operation
"Calculation result"
end
end
user = User.first
puts user.expensive_query # Wait for 2 seconds
puts user.expensive_query # Get cached value
Memoization in before_action in the controller:
class UsersController < ApplicationController
before_action :set_user
def show
render json: { user: @user }
end
private
def set_user
@user ||= User.find(params[:id])
end
end
This helps avoid repeated database queries if the @user method is used multiple times in an action.
How does memoization differ from caching?
In short:
Memoization is storing a result within a single running process (for example, in an instance variable of an object).
Caching is a broader term that can include storing data between processes, in databases, files, Redis, Memcached, etc.
This post doesn't have any additions from the author yet.