In my current work, I’m using (abusing) of the ruby safe operator &, which is a
native implementation of the null pattern,
for example, in a chain of messages:
user.billings.first.cost
It could be thrown an error when for example the billings of a user is empty and
first returns a nil object and then nil.cost creates an Exception.
With the safe operator & this avoids the error:
user.billings.first&.cost # => 5.3838
So, in the last part of the code using the & is not causing an error because the
safe operator logic is:
nil&.any_method # => nil
At the internals, the Ruby language is added with metaprogramming any method
into the class NilClass and that method only returns nil, this is totally
useful to avoid runtime errors.
The problem appears when is needed to compare values, specifically with the
methods ending with ?, check this table:
nil.nil? # returns: true
nil&.nil? # returns: nil
nil.empty? # returns: true
nil&.empty? # returns: nil
nil.blank? # returns: true
nil&.blank? # returns: nil
nil.present? # returns: false
nil&.present? # returns: nil
And evaluating nil in conditionals is false, for example, this trivial code:
if user.store.purchases.empty?
send_email_suggesting_products
end
If the user does not have a store, nil.purchases throws an exception, avoiding
the error the code looks like:
if user.store&.purchases&.empty?
send_email_suggesting_products
end
This code avoids runtime errors but adds a new logic error, this code never
sent an email, that is because nil&.empty? always returns nil if the store
is a nil value.
To avoid this behavior only delete the & at the end, now the code is:
if user.store&.purchases.empty?
send_email_suggesting_products
end
now nil.empty? (in rails) returns the correct true and sends the email.
Conclusion
Use safe operator & with confidence, but when you add to a method that compares
values, avoid or double-check the usage of &.