Safe navigation operator

Ruby 2.3.0 introduces new operator &. which acts like object#try from ActiveSupport.

person = Person.new
puts "Money: #{person&.account&.money}"

Not so simple

You may guest that foo&.bar is equivalent to (foo == nil) ? nil : foo.bar. But it’s not.

def foo 
  obj = nil
  (obj == nil) ? nil : obj.attr
end

foo += 1 # undefined method `+' for nil:NilClass

While using operator &. you are safe.

obj = nil
obj&.attr += 1 # nil

The operator &. checks for nil value and gracefully interrupts whole expression and return nil.

Using with Hashes

The same semantic for Hashes may looks like this

h = {key1: 1, key2: { subkey: 's'} }

p h[:key3]&.[](:subkey)

But it’s better to use dig method since ruby 2.3

p h.dig  :key3, :subkey
p h&.dig  :key3, :subkey # even that safe

Attention

Some cases may lead to misunderstanding.

  • The &. syntax only skips nil but recognizes false. It is not exactly equivalent to the s1 && s1.s2 && s1.s2.s3 syntax. The right interpretation is
    foo&.bar
    (foo == nil) ? nil : foo.bar # almost the same, see above
    
  • You should avoid using nil? check with &. operator. It handles nil already and you may get unexpected result
    nil&.nil? # => nil
    nil.nil? # => true
    
  • The undefined variables are still undefined
    obj&.attr # undefined local variable or method `obj' for main:Object
    obj = 1
    obj&.attr # undefined method `attr' for 1:Integer