Reputation: 23
Like the title, from 2.3.0 ruby version. We can use Safe Navigation Operator(&.) instead of try for dealing with nil value in Rails. But when I use the new syntax, my reviewer told that is not good for reviewer, or someone else about the meaning my code. So I would like to know which syntax I should use when work with nil value?
nil.try(:method)
nil&.method
Upvotes: 1
Views: 534
Reputation: 1244
As mentioned in @dinjas's answer, .try
is a method provided by Rails, whereas &.
is a method that is provided by Ruby itself, and hence, will be usable outside Rails apps as well.
Additionally, the two operators do NOT work in EXACTLY the same manner. The safe navigation operator prevents NoMethodErrors
only for those cases when it is invoked on a value which is nil
. For example:
a = nil
a&.do_something # Result: nil
a = false
a&.do_something # Result: NoMethodError: undefined method `asd' for false:FalseClass
a.try(:do_something) # Result: nil
As seen above, while .try
handles falsy values as well and returns nil
as the response when a method is invoked on an object that does not support it. However, &.
does not handle that and invokes methods on false
as well. The same applies to blank strings.
In terms of what you should use, I believe that decision should be taken by having a discussion with your team. I believe neither of the methods are incorrect and either can be used. However, I would strongly recommend not using BOTH try
and &.
throughout the codebase as that could lead to unintended effects if the codebase grows large.
This blog by Georgi Mitrev describes the safe navigation operator in more depth and I would recommend giving it a read once.
Upvotes: 2
Reputation: 2125
try
is a method provided by Rails' Active Support
The safe-navigation operator is provided by Ruby itself (since version 2.3).
If you were to open a Ruby console (not Rails), and define a method foo
:
def foo
:bar
end
You could see something like the following:
>> nil.try(:foo)
Traceback (most recent call last):
4: from /Users/dinjas/.rbenv/versions/2.6.1/bin/irb:23:in `<main>'
3: from /Users/dinjas/.rbenv/versions/2.6.1/bin/irb:23:in `load'
2: from /Users/dinjas/.rbenv/versions/2.6.1/lib/ruby/gems/2.6.0/gems/irb-1.0.0/exe/irb:11:in `<top (required)>'
1: from (irb):7
NoMethodError (undefined method `try' for nil:NilClass)
>> nil&.foo
=> nil
IMHO, I prefer using Ruby methods over Rails methods as they are usable outside of the context of Rails.
That said, I also feel that whichever you use, it should be used sparingly. In my experience, it's a symptom of writing timid code (see Avdi Grimm's book, Confident Ruby).
Upvotes: 1
Reputation: 144
&.
works like #try!
, not #try
. documentation#try
not native in ruby but it is provided by rails.#&.
is almost 3~4 times faster than using the #try
require 'active_support/all'
require 'benchmark'
foo = nil
puts Benchmark.measure { 10_000_000.times { foo.try(:boo) } }
puts Benchmark.measure { 10_000_000.times { foo&.boo } }
Output
1.210000 0.000000 1.210000 ( 1.211835)
0.360000 0.000000 0.360000 ( 0.363127)
Upvotes: 3