Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Singleton class of singleton class of BasicObject in Ruby

This is mostly an “academic” one but here it goes:

According to this Ruby eigenclass diagram (slightly edited):

Possibly-wrong Ruby eigenclass diagram

BasicObject.singleton_class.singleton_class.superclass is Class.

However, running this on a Ruby interpreter (Ruby v2.5.1), it turns out that BasicObject.singleton_class.singleton_class.superclass is #<Class:Class> and not Class. Therefore, is the diagram lying or am I missing something?

The diagram is from a user I chatted with at Ruby IRC in Freenode. However, it's been quoted multiple times to many other users and it's been treated as the Ruby object model bible.

like image 817
stratis Avatar asked Oct 28 '22 09:10

stratis


1 Answers

The behavior of the Ruby interpreter makes perfect sense because:

  • When a Child class extends a Parent, Ruby sets it up so that the singleton class #<Class:Child> extends #<Class:Parent> as well; and
  • BasicObject.singleton_class is a subclass of Class, so BasicObject.singleton_class.singleton_class will be a subclass of #<Class:Class>

Verifying the equality:

BasicObject.singleton_class.singleton_class.superclass.equal?(Class.singleton_class)
#=> true

This leads to the next question – why does #<Class:BaseObject> extend Class in the first place? Following the rule above, since BaseObject has no superclass – that is, BaseObject.superclass is nil – the logical thing would be for its singleton class to not have a superclass either.

The answer is that #<Class:BaseObject> extending Class ensures consistency in the inheritance hierarchy when it comes to singleton classes. Take this Ruby object for example:

obj = "a string"

It is a well-established notion that instead of obj being simply an instance of String, we can think of it as an (only) instance of its own singleton class, which in turn is a subclass of String. That is:

obj.class.equal?(obj.singleton_class.superclass)
#=> true

It seems only logical that the same should apply to class instances as well. But it does not, because it contradicts the rule mentioned above, where the superclass of a singleton class of a Child class is the singleton class of its Parent class.

class Foo; end

Foo.class
#=> Class

Foo.singleton_class.superclass
#=> #<Class:Object>      <-- not equal to Class!

# because:
Foo.superclass
#=> Object

But it is possible to resolve this contradiction by placing Class at the top of the singleton class inheritance hierarchy:

Foo.singleton_class.superclass
#=> #<Class:Object>

Foo.singleton_class.superclass.superclass
#=> #<Class:BasicObject>

Foo.singleton_class.superclass.superclass.superclass
#=> Class

This way, even though Foo.singleton_class.superclass is not equal to Foo.class, by walking up the inheritance chain, it does get there eventually...

like image 128
Mate Solymosi Avatar answered Nov 08 '22 17:11

Mate Solymosi