Rubyのsetterの返り値 (2)

前回書いた記事 Rubyのsetterの返り値 - tanaken’s blog にコメントをいただきました。(ありがとうございます!!)

https://ruby-doc.org/3.2.1/syntax/methods_rdoc.html#label-Return+Values にどういう挙動をするのかが記載されているとのことで、読んでみましょう。

Note that for assignment methods the return value will be ignored when using the assignment syntax. Instead, the argument will be returned:

"assignment syntax"*1 をつかった "assignment methods"*2 では返り値が無視されるよ、代わりに引数を返すよ。ということですね。

サンプルコードもわかりやすいです。

def a=(value)
  return 1 + value
end

p(self.a = 5) # prints 5

また、sendメソッドを使って該当のメソッドを直接呼び出す場合は返り値が無視されないそうです。

p send(:a=, 5) # prints 6

へぇ〜。

前回の記事で使ったコードでも確認しておくとこんな感じです。

class Bar
  def x=(val)
    @x = val
    'うおぉぉぉおぉぉぉぅぉ'
  end
end
irb(main):001:1* class Bar
irb(main):002:2*   def x=(val)
irb(main):003:2*     @x = val
irb(main):004:2*     'うおぉぉぉおぉぉぉぅぉ'
irb(main):005:1*   end
irb(main):006:0> end
=> :x=
irb(main):007:0> bar = Bar.new
=> #<Bar:0x00000001030f2130>
irb(main):008:0> bar.x = 10
=> 10
irb(main):009:0> bar.send(:x=, 10)
=> "うおぉぉぉおぉぉぉぅぉ"

なるほどねぇ〜。

どういう実装になってるの?

わからんです。

https://github.com/ruby/ruby を "assignment syntax" や "assignment methods" で検索してますが、まだ実装にはたどり着いていません。

parser gemをつかって雑に構文解析をしてみましたが、不慣れでさっぱりです。

text = <<~EOS
def a=(value)
  return 1 + value
end
self.a = 5
EOS
# => "def a=(value)\n  return 1 + value\nend\n\nself.a = 5\n"

Parser::CurrentRuby.parse(text)
# => 
# s(:begin,
#   s(:def, :a=,
#     s(:args,
#       s(:arg, :value)),
#     s(:return,
#       s(:send,                                   
#         s(:int, 1), :+,                          
#         s(:lvar, :value)))),                     
#   s(:send,                                       
#     s(:self), :a=,                               
#     s(:int, 5)))         

ruby の内部実装についての知識をつけないと、どこを探せばいいか見当がつかなそうです。

ここ読むと良いよ〜などあればアドバイスお待ちしてます!

*1:"=" のことかな?

*2:引数を変数に割り当てることを目的としたメソッドのこと?