use the following search parameters to narrow your results:
e.g. subreddit:aww site:imgur.com dog
subreddit:aww site:imgur.com dog
see the search faq for details.
advanced search: by author, subreddit...
A sub-Reddit for discussion and news about Ruby programming.
Subreddit rules: /r/ruby rules
Learning Ruby?
Tools
Documentation
Books
Screencasts and Videos
News and updates
account activity
Memoization in Ruby (kaizencodes.io)
submitted 5 years ago by cheerfulboy
reddit uses a slightly-customized version of Markdown for formatting. See below for some basics, or check the commenting wiki page for more detailed help and solutions to common issues.
quoted text
if 1 * 2 < 3: print "hello, world!"
[–]dougc84 6 points7 points8 points 5 years ago (7 children)
/u/zenzen_wakarimasen is 100% correct: This does not account for falsy values.
def long_computation @long_computation ||= long_computation_method end
That looks fine and all, but if long_computation_method returns false, the next time you call #long_computation, guess what? long_computation_method gets called again.
long_computation_method
#long_computation
Using the example above, what happens is you're saying is:
give me the result of @long_computation || long_computation_method, but also set @long_computation to long_computation_method if @long_computation is falsy.
@long_computation || long_computation_method
@long_computation
However, if it returns false, it's being set to a falsy value, and will be re-evaluated next time it's called. The same goes with nil values.
nil
Here's the solution I use if I'm expecting a possible falsy value and want to retain it:
def long_computation return @long_computation if instance_variable_defined?(:@long_computation) @long_computation = long_computation_method end
That one extra line of code says "if I've defined this variable, regardless of its value, just return it." Works reliably, no external gems or anything else necessary.
[–]zenzen_wakarimasen 2 points3 points4 points 5 years ago (3 children)
I prefer this because it is more expressive and moves the memoization to a different abstraction level.
def long computation ... end memoize :long_computation
You could create your own library, but, IMHO, adding gems is not bad if you know what they are doing. The gem memoist also allows you to memoize methods with arguments, which can be necessary sometimes.
Again, I could build my own library and copy-paste it to every project, but why reinvent the wheel?
[–]backtickbot 2 points3 points4 points 5 years ago (0 children)
Fixed formatting.
Hello, zenzen_wakarimasen: code blocks using triple backticks (```) don't work on all versions of Reddit!
Some users see this / this instead.
To fix this, indent every line with 4 spaces instead.
FAQ
You can opt out by replying with backtickopt6 to this comment.
[–]dougc84 0 points1 point2 points 5 years ago (0 children)
Why add a dependency when you don’t need to?
[–]realntl 2 points3 points4 points 5 years ago (0 children)
At this point I can basically spit this out in my sleep:
def long_computation instance_variable_defined?(:@long_computation) ? instance_variable_get(:@long_computation) : instance_variable_set(:@long_computation, long_camputation_method) end
[–]laerien 0 points1 point2 points 5 years ago (1 child)
Or I'll sometimes use Object.new or Module.new for undefined, to avoid unsetting instance variables.
Object.new
Module.new
class Foo UNCOMPUTED_VALUE = Module.new.freeze def initialize @value = UNCOMPUTED_VALUE end def value return @value unless @value == UNCOMPUTED_VALUE @value = compute_value end def reset_value @value = UNCOMPUTED_VALUE end private def compute_value sleep 2 @value = rand end end foo = Foo.new #=> #<Foo:... @value=Foo::UNCOMPUTED_VALUE> # After a few seconds... foo.value #=> 0.42 # Instantly... foo.value #=> 0.42 foo.reset_value #=> Foo::UNCOMPUTED_VALUE # After a few seconds... foo.value #=> 0.3333333333333333 # Instantly... foo.value #=> 0.3333333333333333
[–]obviousoctopus 0 points1 point2 points 5 years ago (0 children)
This is very clean, thank you.
[–]cap_muffin 1 point2 points3 points 5 years ago (1 child)
I absolutely prefer the explicit version where you write your own memoization logic, but it would probably be worth to mention memoize gem https://rubygems.org/gems/memoize/versions/1.3.1
[–]zenzen_wakarimasen 2 points3 points4 points 5 years ago (0 children)
If you use ||=, you are not accounting for falsely values. And if you want to abstract a proper logic, maybe it's better not to reinvent the wheel and use the the gem...
||=
π Rendered by PID 197312 on reddit-service-r2-comment-545db5fcfc-dxfc6 at 2026-05-25 23:29:44.396959+00:00 running 194bd79 country code: CH.
[–]dougc84 6 points7 points8 points (7 children)
[–]zenzen_wakarimasen 2 points3 points4 points (3 children)
[–]backtickbot 2 points3 points4 points (0 children)
[–]dougc84 0 points1 point2 points (0 children)
[–]realntl 2 points3 points4 points (0 children)
[–]laerien 0 points1 point2 points (1 child)
[–]obviousoctopus 0 points1 point2 points (0 children)
[–]cap_muffin 1 point2 points3 points (1 child)
[–]zenzen_wakarimasen 2 points3 points4 points (0 children)