简体   繁体   中英

Ruby: Safe-navigation operator, undefined method `call`

I am trying to compare a number literal with the return value of a function that could return nil or a numeric. Consider this:

def unreliable
  [nil, 42].sample  
end

unreliable > 10

This will blow up 50% of the time with NoMethodError: undefined method '>' for nil:NilClass . So I tried this:

unreliable&.(:>, 10)

That approach does the nil guarding I expect, but I get this when unreliable returns 42 :

NoMethodError: undefined method `call' for 42:Fixnum

I suspect this has to do with the quirks of allowing only one instance to exist for each Numeric , see here . And I know I can do this:

foo = unreliable
foo && foo > 10

But is there a way to use the safe navigation operator with a numeric and :> , :< , :== , :+ , :- , :/ , :* , etc?


Edit : The focus on Numeric in my question is a red herring. See @Jörg's answer. I was confusing Rails's try syntax with the safe-navigation operator's syntax.

This works fine in Ruby 2.3+ :

unreliable&.> 10

For example :

[-5, 0, nil, 5].each do |unreliable|
  p unreliable&.> 0
end
# false
# false
# nil
# true

The way you tried it, Ruby expects unreliable to be a callable object such as a 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's no need to put parens and the method should be a method name, not a symbol (Rails' try expects a symbol).

I suspect this has to do with the quirks of allowing only one instance to exist for each Numeric

No, this has nothing to do with that at all.

foo.(bar)

is syntactic sugar for

foo.call(bar)

Ergo,

foo&.(bar)

is syntactic sugar for

foo&.call(bar)

So, your code:

 unreliable&.(:>, 10) 

is syntactic sugar for

unreliable&.call(:>, 10)

I'm not sure who told you that the safe-navigation operator takes the message as a symbol argument. The whole point of the safe-navigation operator is that you only have trivial syntactic overhead by adding a single character, the & in front of the . , and the expression is otherwise unchanged.

So,

 unreliable > 10 

which is the same as

unreliable.>(10)

simply becomes

unreliable&.>(10)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM