Ruby でメソッドの戻り値を受け取るかどうかを判定する RubyVM.return_value_is_used? が面白そう
こんな深夜に Ruby で面白そうなチケットを見かけたのでいろいろと試してみました。
- チケット: [Feature #17004] Provide a way for methods to omit their return value
- PR : Provide a way for methods to omit their return value (rev.2) by shyouhei · Pull Request #3271 · ruby/ruby · GitHub
注意
- これはまだ開発中の機能になり今後挙動が変わる可能性があります
- またこの機能はまだ議論されている途中で本体に組み込まれるか未定です
RubyVM.return_value_is_used?
とは
RubyVM.return_value_is_used?
は呼び出したメソッドの戻り値が受け取られるのか受け取られないのかを判定します。
例えば def hoge
の中で RubyVM.return_value_is_used?
を呼び出した場合、 hoge
の戻り値が変数等に代入されれば true
を返し、そうでなければ false
を返します。
使い方は以下のような感じ
def hoge if RubyVM.return_value_is_used? pp "戻り値を受け取る" else pp "戻り値を受け取らない" end end # 戻り値を受け取らない hoge # "戻り値を受け取らない" # 変数に代入する value = hoge # "戻り値を受け取る" # 引数に渡す Array hoge # "戻り値を受け取る" # 戻り値をチェーンする hoge.nil? # "戻り値を受け取る" # 最後に呼び出したやつも? hoge # "戻り値を受け取る"
使い方自体はそこまで難しくなさそうですね。
ただし、以下のように書くと意図せず『戻り値を受け取る』ことになるので注意する必要はありそうです。
def hoge if RubyVM.return_value_is_used? pp "戻り値を受け取る" else pp "戻り値を受け取らない" end end def foo # hoge の戻り値をそのまま返しているので "戻り値を受け取る" ことになる hoge end foo # "戻り値を受け取る" def bar # hoge の戻り値は受け取っていないので "戻り値を受け取らない" ことになる hoge nil end bar # "戻り値を受け取らない"
不要に戻り値を返さないように注意する必要がありそうですね。
ユースケース
いくつかユースケースを考えてみました。
class Hash def refresh(key) # 引数を受け取る場合のみ result を設定する if RubyVM.return_value_is_used? result = self[key] end self[key] = nil result end end homu = { name: "homu", age: 14 } homu.refresh(:name) p homu # => {:name=>nil, :age=>14} age = homu.refresh(:age) pp homu # => {:name=>nil, :age=>nil} pp age # => 14
class User < ActiveRecord::Base def update_name(name) update!(name: name) # 戻り値を受け取る場合のみ reload した値を返す reload if RubyVM.return_value_is_used? end end
こんな感じで副作用を伴うメソッドだと割と多用しそうです。
所感
アプローチとしては面白いですね。
他の言語とかにも似たような機能ってあるんだろうか?
利用できそうなケースは割とありそうだと思いつつ、毎回メソッドを定義するたびに RubyVM.return_value_is_used?
を使って処理を分岐するのは結構しんどそうな気がしました。
実際に使う場合はボトルネックになりそうなケースでのみ使用しそうですかね?使いこなすのがむずかしそう。
すでにチケットや PR のコメントが盛り上がっていますが、導入されると結構な目玉機能になりそうですねー。