Project

General

Profile

Actions

Bug #17321

closed

Having a singleton class makes cloning imperfect

Added by ufuk (Ufuk Kayserilioglu) over 3 years ago. Updated about 3 years ago.

Status:
Closed
Assignee:
-
Target version:
-
ruby -v:
ruby 3.0.0dev (2020-11-11T09:11:09Z master fa3670e6e4) [x86_64-darwin19]
[ruby-core:100801]

Description

Problem


Running the following reproduction script:

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 (Alan Wu) and me have put together a PR that makes Case 2 output identical to Case 1 output:
https://github.com/ruby/ruby/pull/3761

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0