Nil and Ampersand

I discovered an odd feature in Ruby and I don’t know what its called but I know how to use it… Maybe someone can put a name to this.

I can have a function sequence like below and it will produce the length of the first array element

["G4143"].first.length => 5

But if I have an empty array I can still call length(and not have the program crash) if I append an ampersand onto first

[].first&.length => nil

The ampersand acts like a operator that passes nil along if its present. If you have many function calls that have to pass nil…

[].first&.upcase&.length => nil

Does anyone know what this feature is called? I’d like to read the docs but I don’t know what to look up.

This feature was introduced in Ruby 2.3 and its name is Safe navigation operator:
https://ruby-doc.org/core-2.4.0/doc/syntax/calling_methods_rdoc.html

You may use &. to designate a receiver, then my_method is not invoked and the result is nil when the receiver is nil . In that case, the arguments of my_method are not evaluated.

It seems this was the favourite feature of Matz: Ruby 2.3 on Heroku with Matz

2 Likes

I have learnt that it’s called the safe navigation operator.
It returns nil if a method is called on nil.

For example:
[we will back to the array part later on]

100 &.class                                      # => Integer
1 &.next                                         # => 2
2 &.+(5)                                         # => 7

a = 'hello'                                      # => "hello"
# The object id's don't change
p a.equal?(a &.itself)                           # => true

# You are just calling the methods on `a`

# But what if a becomes nil for some reason:
a = nil                                          # => nil
a &.next                                         # => nil

# You see this program didn't just crash!
# We didn't run the next method on nil!

The a becoming nil can be due to various reasons. One is that when you run STDIN.gets on IDE like Atom + Atom Runner / VS Code + Code Runner, STDIN#gets returns nil because the runner can’t accept inputs!
The example on your code is another reason.

# Say you expect a nested array a to contain other array elements. But it's empty
a = []
a.first.length if a.first    # => nil
a.first &.length              # => nil

If you did:

a = []
a.first.length

You would raise the NoMethodError because you are calling a.first, which returns nil, then the length method on nil, which is really not present…

So you avoided a if statement and saved your code from a crash…

So basically the &.something makes your code a bit safer depending on what you are doing!

Do note that if the method after &.meth doesn’t exist, and the object is not nil, it will raise NoMethodError as normal…

Code like:

0 &.index(?a)    # Will raise NoMethodError

Here’s a post from stackoverflow:

https://stackoverflow.com/questions/57812498/how-does-the-method-syntax-safe-navigation-operator-works-in-ruby


Hope this helps a bit…