Reputation: 14911
Is this:
def x?
return @x if @x.present?
@x = #boolean calculation
end
Equivalent to this for boolean values of @x
?
def x?
@x ||= #boolean calculation
end
Upvotes: 2
Views: 235
Reputation: 6603
TL;DR: No
Just to add more examples to the answers already above:
def x1?(new_value)
return @x if @x.present?
@x = new_value
end
def x2?(new_value)
@x ||= new_value
end
say @x
was a Number:
@x = 123
x1?('new value')
@x
# => 123
@x = 123
x2?('new value')
@x
# => 123
# 123 == 123, so this works for `Number`
but let's say @x
was an empty Array:
@x = []
x1?('new value')
@x
# => 'new value'
@x = []
x2?('new value')
@x
# => []
# 'new value' != [], so it doesn't work for empty Array.
^ and there are all other "types" that this doesn't work as well not just empty Array, some of which have already been answered by others here.
Upvotes: 0
Reputation: 10054
It depends.
@x ||= value
is equivalent to
@x = @x || value
which assigns value
to @x
only if @x
is falsy. In Ruby, only false
and nil
are falsy.
Further, #present?
is a concept from Rails (see doc).
Note though that depending on the value that you expect to store in @x
, it might be equivalent. #present?
is simply the negation of #blank?
(also a Rails concept). #blank?
is defined on Object
as follows:
def blank?
respond_to?(:empty?) ? !!empty? : !self
end
Thus, the behavior of the two snippets you posted is guaranteed to be equivalent when @x
contains a value that doesn't define its own #present?
, #blank?
, or #empty?
methods.
Now, FalseClass
and NilClass
both define #blank?
:
def blank?
true
end
TrueClass
also defines #blank?
:
def blank?
false
end
But this is just an optimization as the default implementation from Object
would result in the same values.
Therefore, false
and nil
will return false
for #present?
and true
will return true
for #present?
.
From this we conclude that, in the specific case of storing boolean values in @x
, the behavior of the two snippets is equivalent.
Upvotes: 0
Reputation: 29478
You should not use either option for memoizing boolean
values as both will recalculate if @x
is false
.
present?
is a special kind of rails check that equates to !blank?
and false.blank? #=> true
but even if this was not a boolean check present?
and ||
are not equivalent. For objects that implement empty?
blank defers to that so something that is empty?
is also blank?
and thus is not present?
.
"".present? #=> false
"" || true #=> ""
[].present? #=> false
[] || true #=> []
false.present? #=> false
false || true #=> true
@x ||= some_logic
equates to @x = @x || some_logic
where obviously if @x
is false some_logic
will fire.
If you just want to see if @x
has already been determined to be a value (e.g. not nil
) then you could replace this with
def x?
return @x unless @x.nil?
@x = some_logic
end
Upvotes: 6