In general terms x ||= y
is equivalent to x = x || y
, it's just shorthand. It's implemented as the expanded form, same as &&=
, +=
or -=
.
Most programming languages, Ruby included, will stop executing a logical comparison statement like ||
on the first true value it encounters and return that. Likewise, it will halt on the first false value when using &&
.
In general terms:
false || foo()
This will return false
and not evaluate foo()
.
The pattern 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'll see other versions of this pattern, like:
def arr
@num ||= begin
stuff = [ ]
# ...
stuff
end
end
This handles cases where the initial 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 second pass to not initialize it again? Simple, by that point @num
is already defined as something.
As a note, if you're using values like false
that would evaluate 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 the long-form way if you need to handle false
as well:
def arr
return @num unless num.nil?
@num = false
end
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.