A common misconception is that a ||= b is equivalent to a = a ||= b, but it behaves like a || a = b
In a = a || b, a is set to something by the statement on every run, whereas with a || a = b, a is only set if a is logically false (i.e. if it's nil or false) because || is 'short circuiting'. That is if the left hand side of the || comparison is true, there is no need to check the right hand side.
Memoizataion is a technique you can use to speed up your accessor methods. It caches the results of methods that do time-consuming work, work that only needs to be done onece. In Rails, you see memoization used so often that it even included a module that would memoize methods for you. We will see that later.
The twitter_followers interpreted to:
@twitter_followers = @twitter_followers || twitter_user.followers. That means that you'll only make the network call the first time you call twitter_followers, and future calls will just return the value of the instance variable @twitter_followers
The begin..end creates a block of code in Ruby that can be treated as a single thing. That's why ||= works just as well here as it did before.
The problem is that when right side of the expression returns nil, it will perform the expensive fetches again. So instead of using ||=, consider if / else statement.
In order to understand the above example, let's talk about 'defined?'. 'defined?' is Conditional Execution. defined? operator returns nil if its argument (which can be an arbitrary expression) is not defined, otherwise it returns a description of that argument. If the argument is yield, defined? returns the string 'yield' if a code block is associated with the current context. Here are the examples.
So go back to the our exmample of @twitter_followers, if it returns nil, instead of it will run and try to set @twitter_followers, it will be just nil.
We have some memoization patterns that work well for simple accessors. But what if you want to memoize a method that takes parameters?
It turns out that Ruby's Hash has an initalizer that works perfectly for this situation. Before going into this, let's look at what new { |hash, key| block } statement.
The block passed after the new keyword is pattern to create default value. When you pass block after Hash.new, it will creates a new default object each time. For instance
Now, look at this example
No matter what you pass into order_by, the correct result will get memoized.Since the block is only called when the key doesn't exist, you don't have to worry about the result of the block being nil or false.