a ||= b is the same as saying a = b if a.nil? or a = b unless a
But do all 3 options show the same performance? With Ruby 2.5.1 this
1000000.times do
a ||= 1
a ||= 1
a ||= 1
a ||= 1
a ||= 1
a ||= 1
a ||= 1
a ||= 1
a ||= 1
a ||= 1
end
takes 0.099 Seconds on my PC, while
1000000.times do
a = 1 unless a
a = 1 unless a
a = 1 unless a
a = 1 unless a
a = 1 unless a
a = 1 unless a
a = 1 unless a
a = 1 unless a
a = 1 unless a
a = 1 unless a
end
takes 0.062 Seconds. That's almost 40% faster.
and then we also have:
1000000.times do
a = 1 if a.nil?
a = 1 if a.nil?
a = 1 if a.nil?
a = 1 if a.nil?
a = 1 if a.nil?
a = 1 if a.nil?
a = 1 if a.nil?
a = 1 if a.nil?
a = 1 if a.nil?
a = 1 if a.nil?
end
which takes 0.166 Seconds.
Not that this will make a significant performance impact in general, but if you do need that last bit of optimization, then consider this result.
By the way: a = 1 unless a is easier to read for the novice, it is self-explanatory.
Note 1: reason for repeating the assignment line multiple times is to reduce the overhead of the loop on the time measured.
Note 2: The results are similar if I do a=nil nil before each assignment.
Ruby's short circuit evaluation means that if a is defined and evaluates to truthy, then the right hand side of the operator is not evaluated, and no assignment takes place. This distinction is unimportant if a and b are both local variables, but is significant if either is a getter/setter method of a class.
Confusingly, it looks similar to other assignment operators (such as +=) but behaves differently.
a += b translates to a = a + b
a ||= b roughly translates to* a || a = b
*Except that, when a is undefined, a || a = b would be NameError, whereas a ||= b sets a to b.
is
"if x is false or undefined, then x point to y"
as a common misconception a||=b is not equivalent to a = a||b but it is but it behaves like a || a = b
But here comes a tricky case
If a is not defined, a || a = 42 raises NameError, while a ||= 42 returns 42. So, they don't seem to be equivalent expressions.
unless x x = y end
unless x has a value (it's not nil or false), set it equal to y
is equivalent to
x ||= y
Please also remember that
||=
isn't an atomic operation and so, it isn't thread safe. As rule of thumb, don't use it for class methods.a ||= b
is the same as sayinga = b if a.nil?
ora = b unless a
But do all 3 options show the same performance? With Ruby 2.5.1 this
takes 0.099 Seconds on my PC, while
takes 0.062 Seconds. That's almost 40% faster.
and then we also have:
which takes 0.166 Seconds.
Not that this will make a significant performance impact in general, but if you do need that last bit of optimization, then consider this result. By the way:
a = 1 unless a
is easier to read for the novice, it is self-explanatory.Note 1: reason for repeating the assignment line multiple times is to reduce the overhead of the loop on the time measured.
Note 2: The results are similar if I do
a=nil
nil before each assignment.a ||= b
is a "conditional assignment operator". It is sort-of-but-not-quite(*) shorthand fora || a = b
.It means "if
a
is undefined or falsey (false
ornil
), then evaluateb
and seta
to the result".For example:
Ruby's short circuit evaluation means that if
a
is defined and evaluates to truthy, then the right hand side of the operator is not evaluated, and no assignment takes place. This distinction is unimportant ifa
andb
are both local variables, but is significant if either is a getter/setter method of a class.Confusingly, it looks similar to other assignment operators (such as
+=
) but behaves differently.a += b
translates toa = a + b
a ||= b
roughly translates to*a || a = b
*Except that, when
a
is undefined,a || a = b
would be NameError, whereasa ||= b
setsa
tob
.Further reading: