In Ruby, there are two values that are considered logical false. The first is the boolean value false, theother is nil. Anything which is non-nil andnot explicitly false is true. Thefirst time though the method, @num is nil,which is treated as false and the logical orportion of ||= needs to be evaluated and ends upassigning the empty array to @num. Since that's now non-nil, itequates to true. Since true || x is true no matter what x is, in future invocations Ruby short circuits the evaluation and doesn't do the assignment.
Ingeneral terms x ||= y is equivalent to x = x || y, it's just shorthand. It's implemented as the expandedform, same as &&=, +=or -=.
Thepattern is best described as a "lazy initializer", that is the
variable is defined only once, but only when it's actually used. This is in
contrast to an "eager initializer" that will do it as early as
possible, like inside the initialize method.
You'llsee other versions of this pattern, like:
@num ||= begin
stuff = [ ]
This handles cases where theinitial value is not as trivial and may need some work to produce. Once again,
it's only actually generated when the method is called for the first time.
How does Ruby know on the secondpass to not initialize it again? Simple, by that point @num is already defined as something.
As a note, if you're using valueslike false that wouldevaluate as non-true, then ||=will trigger every time. The only two logically false values in Ruby are nil and false, so most of the time this isn't an issue.
You'll have to do this thelong-form way if you need to handle falseas well:
return @num unless num.nil?
@num = false
There was talk of adding an ||=-like operator that would only trigger on nil but I don't think that has been added to Ruby yet.