From: ufuk@... Date: 2020-11-24T19:44:42+00:00 Subject: [ruby-core:101053] [Ruby master Bug#17321] Having a singleton class makes cloning imperfect Issue #17321 has been updated by ufuk (Ufuk Kayserilioglu). @jeremyevans0 Thanks for closing the issue. Can we get this fix backported to 2.5, 2.6 and 2.7 please? As noted in the original report, this bug is present on all the way back to 2.0. Thank you! ---------------------------------------- Bug #17321: Having a singleton class makes cloning imperfect https://bugs.ruby-lang.org/issues/17321#change-88725 * Author: ufuk (Ufuk Kayserilioglu) * Status: Closed * Priority: Normal * ruby -v: ruby 3.0.0dev (2020-11-11T09:11:09Z master fa3670e6e4) [x86_64-darwin19] * Backport: 2.5: UNKNOWN, 2.6: UNKNOWN, 2.7: UNKNOWN ---------------------------------------- ## Problem --- Running the following reproduction script: ```ruby class Foo def self.foo; end end def report(klass, name) puts " #{name}.instance_methods(false): #{klass.instance_methods(false)}" end def clone_and_compare(obj) cln = obj.clone report(obj.singleton_class, "obj.singleton_class") report(cln.singleton_class, "cln.singleton_class") report(obj.singleton_class.singleton_class, "obj.singleton_class.singleton_class") report(cln.singleton_class.singleton_class, "cln.singleton_class.singleton_class") end puts "## Case 1" obj = Foo.new clone_and_compare(obj) puts "## Case 2" obj = Foo.new obj.singleton_class clone_and_compare(obj) puts "## Case 3" obj = Foo.new obj.singleton_class.singleton_class.send(:define_method, :method_on_s2) {} clone_and_compare(obj) ``` gives the following output: ``` ## Case 1 obj.singleton_class.instance_methods(false): [] cln.singleton_class.instance_methods(false): [] obj.singleton_class.singleton_class.instance_methods(false): [] cln.singleton_class.singleton_class.instance_methods(false): [] ## Case 2 obj.singleton_class.instance_methods(false): [] cln.singleton_class.instance_methods(false): [] obj.singleton_class.singleton_class.instance_methods(false): [] cln.singleton_class.singleton_class.instance_methods(false): [:foo] ## Case 3 obj.singleton_class.instance_methods(false): [] cln.singleton_class.instance_methods(false): [] obj.singleton_class.singleton_class.instance_methods(false): [:method_on_s2] cln.singleton_class.singleton_class.instance_methods(false): [:method_on_s2] ``` `Case 2` is surprising, because the cloned object has different contents to the original. It is surprising that `clone.singleton_class.singleton_class` has the method `:foo` whereas `obj.singleton_class.singleton_class` does not have any methods. `Case 3` suggests, however, that `clone.singleton_class.singleton_class` should have the same methods as the ones on `obj.singleton_class.singleton_class`. This reproduction script gives the same output all the way from Ruby 2.0 up to Ruby-HEAD: https://wandbox.org/permlink/hRM9OMgtd6nuscRz ## Fix --- @alanwu and me have put together a PR that makes `Case 2` output identical to `Case 1` output: https://github.com/ruby/ruby/pull/3761 -- https://bugs.ruby-lang.org/ Unsubscribe: