The last post on the basics of memoization covered what memoization was, how you can use it in your application, and some of the potential pitfalls.
In this post we’ll look at advanced assignment techniques, we’ll fix where basic memoization can fail, and you’ll see how to perform a more advanced memoization.
To refresh your memory, here’s a really basic example of memoization using the conditional assignment operator:
1 2 3
Most times you can use a straight up single statement for performing memoization. But as your application grows you’re going to need additional, more expressive ways to perform memoization and build complex objects.
Because Ruby is so awesome you can do memoization assignment with an
1 2 3 4 5
It came as a real surprise to me when I found out that you can assign the results of an if/else to a variable. Another surprise was being able to use
end, like this:
1 2 3
These are two ways you can write a more advanced memoization method.
Where Conditional Assignment Fails
If you’re not careful, conditional assignment can bite you in the butt! Try this code in
1 2 3 4 5 6 7 8 9 10 11 12 13
"hit" was printed twice? It turns out the conditional assignment operator is trickier than you thought!
Conditional assignment is always going to run if the variable
@foo is falsely — that is if the value of
Now it’s fairly rare to have code return false in a memoization scenario, but in the event that your code does, you can get around it using
if_defined? and a guard return:
1 2 3 4 5 6 7 8 9 10 11 12
This is a safer pattern to use when writing your memoization code, but more verbose versus the idiomatic Ruby version described previously. My personal preference is to use this only when it’s needed.
Memoizing with Parameters
In the last post on memoization one of the places I recommended not to use memoization was with parameterized methods. That was partially true because conditional assignment doesn’t handle parameters. However, you can get around that limitation by using a
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
At this point you’re effectively re-implementing a cache. And to be perfectly honest, there are people smarter than you and I that have worked long and hard on cache, so there’s no point reinventing the wheel there! Cache on the other hand, is a future topic to dive into!
There is one final thing if you’re really looking to use a memoize technique verses cache, and that is to use the memoizable gem. Originally this code was within Rails itself, but was pulled out and moved into it’s own seperate gem. It’s overkill for something like a
current_user memoization but works great to keep you from implementing the code above!
That wraps up the post on advanced memoization. While this post focused on memoization techniques that are applicable to Ruby (and Rails), the primary focus of this blog is improving Rails performance. If you want to receive regular tips on improving Rails performance add your name in the below box: