From: "jeremyevans0 (Jeremy Evans) via ruby-core" Date: 2025-08-30T00:16:36+00:00 Subject: [ruby-core:123131] [Ruby Bug#21538] initialize_dup not called when duping class/module Issue #21538 has been updated by jeremyevans0 (Jeremy Evans). The example given isn't a bug. `initialize_dup` is called on the new instance (in this example, the instance of `Class`), and `dup` does not copy singleton classes. If you define `Class#inititialize_dup`, it works as expected: ```ruby class A def initialize_dup(_) puts "dup instance" super end end class Class def initialize_dup(_) puts "dup class" super end end A.new.dup # prints "dup instance" A.dup # prints "dup class" ``` `dup` is different than `clone`, because `clone` copies the singleton class, and therefore will pick up singleton methods: ```ruby class A def initialize_clone(_) puts "clone instance" super end def self.initialize_clone(_) puts "clone class" super end end A.new.clone # prints "clone instance" A.clone # prints "clone class" ``` That being said, there are two definite bugs and another probable bug in `Class#dup`, as evidenced by this example: ```ruby class Class def initialize_dup(_) p ancestors p singleton_class.ancestors super end end class B def self.initialize_dup(_) puts "dup class" super end end class A < B end puts p A.ancestors p A.singleton_class.ancestors puts C = A.dup puts p C.ancestors p C.singleton_class.ancestors ``` Output on Ruby 3.4 (with comments on bugs): ``` [A, B, Object, Kernel, BasicObject] [#, #, #, #, Class, Module, Object, Kernel, BasicObject] # Probable Bug: During initialize_dup, ancestors are missing, # and therefore ancestor initialize_dup singleton method not called [#] [#>, Class, Module, Object, Kernel, BasicObject] # Definite Bug 1: after dup, singleton class ancestors are missing [C, B, Object, Kernel, BasicObject] [#, Class, Module, Object, Kernel, BasicObject] ``` Output on master branch: ``` [A, B, Object, Kernel, BasicObject] [#, #, #, #, Class, Module, Object, Kernel, BasicObject] # Definite Bug 2: calling singleton_class inside Class#initialize_dup # results in TypeError [#] [#>, Class, Module, Object, Kernel, BasicObject] -:5:in 'Module#initialize_copy': already initialized class (TypeError) from -:5:in 'Kernel#initialize_dup' from -:5:in 'Class#initialize_dup' from -:25:in 'Kernel#dup' from -:25:in '
' ``` The reason I call the first bug probable and not definite is that it is at least defensible that ancestor setup occurs inside `dup`, but after the call to `Class#initialize_dup`. I still think it should be considered a bug and fixed. I'm guessing fixing definite bug 2 requires fixing the probable bug. For `clone`, there is a similar issue of missing ancestors (but not singleton class ancestors) inside `initialize_clone`: ```ruby class B def self.initialize_clone(_) p ancestors p singleton_class.ancestors puts "clone class" super end end class A < B end puts p A.ancestors p A.singleton_class.ancestors puts C = A.clone puts p C.ancestors p C.singleton_class.ancestors ``` Output: ``` [A, B, Object, Kernel, BasicObject] [#, #, #, #, Class, Module, Object, Kernel, BasicObject] # Probable bug: During initialize_clone, ancestors are missing [#] [#>, #, #, #, Class, Module, Object, Kernel, BasicObject] clone class [C, B, Object, Kernel, BasicObject] [#, #, #, #, Class, Module, Object, Kernel, BasicObject] ``` ---------------------------------------- Bug #21538: initialize_dup not called when duping class/module https://bugs.ruby-lang.org/issues/21538#change-114458 * Author: chucke (Tiago Cardoso) * Status: Open * ruby -v: 3.4.5 * Backport: 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN ---------------------------------------- Not sure whether this is expected behaviour or not, but just leaving it here to start the debate on whether callbacks like `initialize_dup` are supposed to be called when a module or class is duped (the same happens with `initialize_copy` and `initialize_clone` btw): class A def initialize_dup(_) puts "dup instance" super end def self.initialize_dup(_) puts "dup class" super end end A.new.dup #=> "dup instance" A.dup #=> nothing -- https://bugs.ruby-lang.org/ ______________________________________________ ruby-core mailing list -- ruby-core@ml.ruby-lang.org To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/