Ruby: safe navigation operator, undefined `call` method
I am trying to compare a numeric literal with the return value of a function that can return nil
or numeric. Consider this:
def unreliable
[nil, 42].sample
end
unreliable > 10
This will explode 50% of the time with NoMethodError: undefined method '>' for nil:NilClass
. So I tried this:
unreliable&.(:>, 10)
This approach protects nil
, but I get this when it unreliable
returns 42
:
NoMethodError: undefined method `call' for 42:Fixnum
I suspect this is due to quirks of only allowing one instance to exist for each Numeric
, see here . And I know I can do this:
foo = unreliable foo && foo > 10
But there is a way to use the safe navigation operator with numerical and :>
, :<
, :==
, :+
, :-
, :/
, :*
, etc.
Edit . The focus on Numeric
my question is the red herring. See @ Jörg's answer. I was confusing the Rails try
syntax with the safe navigation statement syntax.
source to share
This works great in Ruby 2.3+:
unreliable&.> 10
For example:
[-5, 0, nil, 5].each do |unreliable|
p unreliable&.> 0
end
# false
# false
# nil
# true
As you tried it, Ruby expects to unreliable
be a callable object, for example Proc
:
unreliable = Proc.new{ |*params| puts "unreliable has been called with #{params}" }
unreliable&.(:>, 10)
# unreliable has been called with [:>, 10]
unreliable.call(:>, 10)
# unreliable has been called with [:>, 10]
unreliable&.call(:>, 10)
# unreliable has been called with [:>, 10]
unreliable[:>, 10]
# unreliable has been called with [:>, 10]
With the safe navigation operator, there is no need to put pairs and the method must be a method name, not a symbol (Rails try
expects a symbol).
source to share
I suspect this is due to quirks of allowing only one instance to exist for each
Numeric
No, it has nothing to do with it.
foo.(bar)
- syntactic sugar for
foo.call(bar)
Ergo,
foo&.(bar)
- syntactic sugar for
foo&.call(bar)
So your code:
unreliable&.(:>, 10)
- syntactic sugar for
unreliable&.call(:>, 10)
I'm not sure who told you that the safe navigation operator takes a message as a character argument. The whole point of the safe navigation statement is that you only have trivial syntactic overhead, adding one character &
before .
, and the expression is otherwise unchanged.
So,
unreliable > 10
which is the same as
unreliable.>(10)
just becomes
unreliable&.>(10)
source to share