🎃
[Misc #21143] const_added と inherited の実行順に関するチケット
[Misc #21143] Speficy order of execution const_added vs inherited
-
.const_added
と.inherited
の実行順に関するチケット - 以下のコードを実行すると
.const_added -> .inherited
順で実行されることがわかります
module M
class C
def self.inherited(subclass)
pp ".inherited: #{subclass}"
end
end
def self.const_added(cname)
pp ".const_added: #{cname}"
end
class D < C; end
end
__END__
".const_added: D"
".inherited: M::D"
-
.const_added
は定数が定義されたときに呼ばれる
メソッド- 上記の場合だと
D
が定義されたときに呼ばれる
- 上記の場合だと
-
.inherited
は継承されたときに呼ばれる
メソッド- 上記の場合だと
D < C
されたときに呼ばれる
- 上記の場合だと
- なので
.inherited
が呼び出されたタイミングでは『既にD
がC
を継承している状態』として扱われるようになる - このチケットではこの実行順を明文化しよう、というチケット
- Zeitwerk がこの挙動に依存しているので明文化したい、みたいなモチベーションみたいですね
- これなんですがコードの書き方によって期待する順番が違ったりするみたいで色々と難しそうですね
- 例えば以下のように
Class.new
をした場合は.const_added -> .inherited
の順で呼び出されたりします- これは定数定義の前に
Class.new
の時点で継承の処理がされたりする関係 - https://bugs.ruby-lang.org/issues/21143#note-3
- これは定数定義の前に
module M
class C
def self.inherited(subclass)
pp ".inherited: #{subclass}"
end
end
def self.const_added(cname)
pp ".const_added: #{cname}"
end
D = Class.new(C)
end
__END__
".inherited: #<Class:0x000077cfd57f83f8>"
".const_added: D"
- こういうのを考慮すると
inherited -> const_added
の順で呼び出すようにする話もでたりしていますね- matz もこれには同意しています
- https://bugs.ruby-lang.org/issues/21143#note-6
- これなんですが最終的には Ruby 3.5 から
inherited -> const_added
の順で呼び出されるように対応されました
$caller = []
module M
class C
def self.inherited(subclass)
$caller << ".inherited: #{subclass}"
end
end
def self.const_added(cname)
$caller << ".const_added: #{cname}"
end
class D < C; end
end
pp $caller
# Ruby 3.4 => [".const_added: D", ".inherited: M::D"]
# Ruby 3.5 => [".inherited: M::D", ".const_added: D"]
- Zeitwerk 関連でどれぐらい影響があるんですかねえ
Discussion