🙄

【bugs.ruby Advent Calender】【16日目】

2024/12/16に公開

bugs.ruby Advent Calender 16日目の記事です。

これはなに

今年1年間通してみてきた bugs.ruby のチケットの中から気になったものを1つずつ取り上げていく Advent Calender です。
取り上げるチケットは基本的にこのブログで取り上げたものになります。
記事のまとめは ここを参照 してください。

[Bug #20643] Ruby 3.2 behavior change for protected and private methods when yield self

チケットの内容は Symbol#to_proc 経由でメソッドを呼び出したときの挙動が Ruby 3.2 から変わってしまったバグ報告になります。
具体的には以下のように private メソッドを呼び出したときの挙動が変わります。

class Foo
  private

  def bar
    "private method bar called"
  end
end

# 内部では Foo.new { _1.bar } が呼び出される
pp Foo.new.then(&:bar)
# Ruby 3.1 => ok: "private method bar called"
# Ruby 3.2 => error: private method `bar' called for an instance of Foo (NoMethodError)

これなんですが実は [Bug #18826] Symbol#to_proc inconsistent, sometimes calls private methods の対応で意図する変更になります。

#18826 のチケットは『 Symbol#to_proc で private メソッドが呼び出されてしまう』というチケットになります。
例えば次のようにブロック内で private メソッドを呼び出すと当然エラーになります。

class Foo
  private

  def bar
    "private method bar called"
  end
end

# error: private method `bar' called for #<Foo:0x000073677ecc8e50> (NoMethodError)
pp Foo.new.then { |it| it.bar }

しかし Symbol#to_proc 経由で private メソッドを呼び出した場合はこれがエラーになりません。

class Foo
  private

  def bar
    "private method bar called"
  end
end

# .then { |it| it.bar } と同じ意味であればエラーになってほしい
pp Foo.new.then(&:bar)

これが挙動として正しくないということで Ruby 3.2 からは Symbol#to_proc では private / protected メソッドは呼び出されなくなりました。
対応としてはバグ修正なんですが挙動としては非互換になるのでこういう変更は注意したいところですね。

関連

GitHubで編集を提案

Discussion