Help us understand the problem. What is going on with this article?

Safe Navigation Operator で呼ばれるメソッドの引数はレシーバが nil なら評価されない

More than 3 years have passed since last update.

タイトルの通りです。

Safe Navigation Operator に関するコミット を追いかけていると、ドキュメント中に興味深い一文が見つかりました。

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.

これは例えば obj&.my_method(arg) というメソッド呼び出しを行った時、 objnil だったら my_method への引数である arg は評価されない、ということです。

試してみる

早速試してみました。

オブジェクトに対して正しくメソッドを呼び出せたとき

safe1.rb
class Foo
  def my_method(s)
    "Foo#my_method is called with \"#{s}\""
  end
end

def arg
  puts "arg is evaluated"
  "m"
end

obj = Foo.new
puts obj&.my_method(arg)
$ ruby safe1.rb
arg is evaluated
Foo#my_method is called with "m"

obj.my_method の結果が出力される前に、arg が評価されていることがわかります。
何の違和感もありません。

レシーバのオブジェクトにメソッドが存在しなかったとき

safe2.rb
class Foo
end

def arg
  puts "arg is evaluated"
  "m"
end

obj = Foo.new
puts obj&.my_method(arg)
$ ruby safe2.rb
arg is evaluated
safe.rb:10:in `<main>': undefined method `my_method' for #<Foo:0x007fe859807020> (NoMethodError)
Did you mean?  method

NoMethodError が発生する前に arg が評価されていることがわかります。
これも特に違和感のない挙動です。

レシーバが nil だったとき

そしていよいよドキュメントに記載されているケースです。

safe3.rb
def arg
  puts "arg is evaluated"
  "m"
end

obj = nil
puts obj&.my_method(arg)
$ ruby safe3.rb

putsnil が渡されることで空行を出力しますが、arg は評価されていないことがわかります。

どういうときにうれしいか

これはやはり引数の評価に時間がかかるような場合、不要な評価を行わない分だけ実行時間を節約できます。

foo&.bar(some_heavy_computation_result)

この some_heavy_computation_result は何か重い処理を行うメソッドだったとして、foonil なら不要であるところのその呼び出しを省略してくれます。
ActiveSupportObject#try! に比べて高速、という記事も書きましたが、これは通常のライブラリでは実現できない最適化です。
逆に言うとレシーバが nil であろうと引数が評価されることを期待していると、そのようには動かないので注意が必要です。

yuya_takeyama
Ruby / PHP / JavaScript / Golang
http://yuyat.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした