Issue #17321 has been reported by ufuk (Ufuk Kayserilioglu).

----------------------------------------
Bug #17321: Having a singleton class makes cloning imperfect
https://bugs.ruby-lang.org/issues/17321

* Author: ufuk (Ufuk Kayserilioglu)
* Status: Open
* 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: <mailto:ruby-core-request / ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>