💡
[Bug #21375] Set[] で #initialize が呼び出されなくなったというバグ報告
[Bug #21375] Set[] does not call #initialize
-
Set[]で#initializeが呼び出されなくなったというバグ報告 - どういうことかというと以下のように
Setを継承したサブクラスで#initializeを定義している場合にMySet[]を呼び出すと Ruby 3.4 ではMySet#initializeが呼び出されていたのが Ruby 4.0-dev では呼び出されなくなった
require "set"
class MySet < Set
def initialize(enum = nil)
super
compare_by_identity
end
end
pp MySet.new.compare_by_identity?
# Ruby 3.4 => true
# Ruby 4.0 => true
pp MySet[].compare_by_identity?
# Ruby 3.4 => true
# Ruby 4.0 => false
- これは Ruby 4.0 から
Setがコアクラスに移動し、実装が変わった影響になる- [Feature #21216] Implement Set as a core class
-
[Feature #21216] の影響で既存の挙動が壊れているものは他にもいくつかあるんですよねえ
- だいたいは明文化されていない挙動に依存している系になっていますが
- 元々
Set[]で#initializeが呼び出されることは明文化されておらず、かつ、Array.[]やHash.[]でも#initializeが呼び出されないのでそちらの挙動に合わせた形になる - また
#initializeを呼び出さないモチベーションとしてはパフォーマンスに影響が出ることが懸念されている - 一方で『
Set.[]に限らず新しいオブジェクトを生成する場合には#initializeが呼び出されることを期待する』という話も上がっている- これは
Array.[]でもそうしようという意図で - https://bugs.ruby-lang.org/issues/21375#note-6
- これは
- そもそも前提なんですが
ArrayやHashはあんまりサブクラス化することはないんですがSetはその限りではないみたいなんですよねえ- なので
Setをサブクラスにしたときの互換性でいろいろと問題が報告されている -
https://bugs.ruby-lang.org/issues/21375#note-8 でも
concurrent-rubyが壊れていると報告されている
- なので
- これなんですが最終的には
Setの挙動は互換性を保つように対応されました
# 最終的な動作
class MySet < Set
def initialize(enum = nil)
super
compare_by_identity
end
end
pp MySet.new.compare_by_identity?
# Ruby 3.4 => true
# Ruby 4.0 => true
pp MySet[].compare_by_identity?
# Ruby 3.4 => true
# Ruby 4.0 => true
Discussion