Today I Learned

Safe Navigation Operator

If you have worked in a Rails project, you have probably came across the try and try! methods. try saves us from checking conditions before drilling-down through a message chain. try! is more restrictive; it raises when the receiver does not respond to the method:

require "active_support"
require "active_support/core_ext/object/try"

User = Struct.new(:name)

users = [User.new("Jason")]

users.first.try(:name)
# "Jason"

users.first.try(:unknown_method)
# nil

users.first.try!(:unknown_method)
# NoMethodError: undefined method `unknown_method' for #<struct User name="Jason">

Note these methods are provided by ActiveSupport. As of Ruby 2.3, this behaviour is now available in the language, called the safe navigation operator &.:

users = [User.new(name: "Jason")]
users.first&.name
# "Jason"

users = []
users.first&.name
# nil

Gotchas

When an object does not respond to a method, &. behaves like try!; it raises an error. However, nil seems to break this pattern:

# behaviour like try!
user&.unknown_method
# NoMethodError: undefined method `unknown_method' for #<struct User name="Jason">

# given that
nil.nil?
# true

# this is confusing
nil&.nil?
# nil

The last example has a simple explanation: &. checks the receiver. Since the receiver is nil, &. immediately returns nil. It does not matter that nil responds to the message.