Ruby - Safe Navigation Operator
- Intro
- Understanding the Exception
- Problematic Example
- A Fix for Our Example
- A Better Fix: Safe Navigation Operator
- Thoughts for the reader:
Intro
If you’ve been programming in Ruby for any amount of time, you’ve probably seen an error like this:
NoMethodError: undefined method 'methodname' for nil:NilClass
Understanding the Exception
The meaning is actually pretty straightforward if you think about it. We’re trying to call a method called “methodname” that is not defined for the object we’re calling it on. In this case, that object is nil
:
a = nil
a.methodname()
#=> NoMethodError: undefined method `methodname' for nil:NilClass
However, nil
isn’t special here, other classes do throw the same error:
a = "string"
a.methodname()
#=> NoMethodError: undefined method `methodname' for "string":String
We’re only really focusing on the case where an undefined method is called on nil
though. I just thought it was important to point out.
Anyways, probably the most common method you’ll see this happen with is: []
NoMethodError: undefined method `[]' for nil:NilClass
Problematic Example
You might see something like this when you’re pulling data from a network socket:
loop do
data = @socket.gets(1024)
puts data.unpack('A*')
end
In the above code, we assumed that every time we call gets
, it’s going to return a String
. When the server closes the socket and we gets
again, we’re going to get a nil
, and unpack
is going to throw NoMethodError
:
#=> NoMethodError: undefined method `unpack' for nil:NilClass
A Fix for Our Example
Let’s fix it:
loop do
data = @socket.gets(1024)
if data != nil
puts data.unpack('A*')
end
end
Well, that’s pretty tedious, there must be a better way…
Enter, the safe navigation operator!: &
A Better Fix: Safe Navigation Operator
loop do
data = @socket.gets(1024)
puts data&.unpack('A*')
end
That’s it, did you even notice? All we have to do is put a &
between our possibly-nil object, and the method being called on it. If the object is nil
, the method won’t be called, and nil
will be returned instead of an exception.
So much easier than checking every single item manually!
Thoughts for the reader:
- Is there a better way to handle this?
- Where else might you run into errors like this?