前回書いた記事 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 の内部実装についての知識をつけないと、どこを探せばいいか見当がつかなそうです。
ここ読むと良いよ〜などあればアドバイスお待ちしてます!