TLDR;
Do this:
def expensive_method
@_expensive_method ||= #something
end
Not this:
def expensive_method
@expensive_method ||= #something
end
Memoization Basics
The act of “memoizing” a method means to locally cache the result of an expensive operation on the first method invocation and reusing it thereafter.
It is functionally equivalent to:
def expensive_method
@expensive_method = @expensive_method || this_expensive_operation
end
Naming
By convention, you typically see developers name the instance variable after the method. Likely, this is because manual instance variable accessors used to look like this:
def expensive_method
@expensive_method
end
Nowadays, we usually write attr_reader :expensive_method
.
Unused Variables
Keen readers will note we are actually instantiating an instance variable here. That means we can access it from other instance methods. Not a huge deal, but it’s intended for internal use when memoizing.
Enter the underscore.
It is convention in many languages including Ruby to prepend an unused variable name with an underscore.
The underscore serves as a signal to other developers saying “Hey! Don’t use this!”.
We should do the same when memoizing:
def expensive_method
@_expensive_method ||= #something
end
This is, of course, a style preference with no functional impact. It’s also just my opinion, man.
Instance Variables in Controllers
Also, as my friend Gabe pointed out to me, it’s even more important to use an underscore when memoizing in Rails controllers:
“Since all controller ivars are available in the view, it’s often helpful to mark ivars that should only be used in the controller with a leading underscore. That also allows things like this, where
@users
is exposed to the view and@_users
is just used for memoization:”def index @posts = posts.where(user: users.where(has_post: true)) @users = users.where(confirmed: true) end private def users @_users ||= User.all end
It’s good to have smart friends.
Further Reading
- Justin Weiss has a nice article on Memoization including links to the history in Rails, handling nil results, and more.
- Vaidehi Joshi has a nice bit on the history of memoization itself. She writes about how it dates back to 1968. (!)
- Gavin Miller wrote a great article covering when to memoize and when not to.
- Some gems which make this easier: memoist, memist