💡

[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 がコアクラスに移動し、実装が変わった影響になる
  • 元々 Set[]#initialize が呼び出されることは明文化されておらず、かつ、 Array.[]Hash.[] でも #initialize が呼び出されないのでそちらの挙動に合わせた形になる
  • また #initialize を呼び出さないモチベーションとしてはパフォーマンスに影響が出ることが懸念されている
  • 一方で『 Set.[] に限らず新しいオブジェクトを生成する場合には #initialize が呼び出されることを期待する』という話も上がっている
  • そもそも前提なんですが ArrayHash はあんまりサブクラス化することはないんですが Set はその限りではないみたいなんですよねえ
  • これなんですが最終的には 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
GitHubで編集を提案

Discussion