Home > Blockchain >  How and why is the super class of singleton_class of BasicObject is Class class in Ruby?
How and why is the super class of singleton_class of BasicObject is Class class in Ruby?

Time:12-21

By definition, a singleton class of an object also inherits the singleton class of the superclass of the object. The BasicObject in ruby doesn't have any superclass as it is the most basic level class

>> BasicObject.superclass
=> nil

But when the same method called on its singleton class, it results:

>> BasicObject.singleton_class.superclass
=> Class

and also why no other object in ruby have the Class class as its superclass?

How the logic behind the superclass of singleton_class of BasicObject is implemented in Ruby?

CodePudding user response:

By definition, a singleton class of an object also inherits the singleton class of the superclass of the object.

Instead of taking this for granted, let's figure out why it was implemented this way.

In Ruby, there are instance methods and class methods. The class methods however are in fact instance methods of the singleton class:

class MyClass
  def foo
  end

  def self.bar
  end
end

MyClass.instance_methods(false)
#=> [:foo]

MyClass.singleton_class.instance_methods(false)
#=> [:bar]

As a diagram:

MyClass  --->  #<Class:MyClass>
foo            bar

Now, if you create a subclass MySubClass, it inherits both, the instance methods and the class methods from its superclass MyClass:

class MySubClass < MyClass
end

MySubClass.instance_methods
#=> [:foo, ...]

MySubClass.singleton_class.instance_methods
#=> [:bar, ...]

To get this working, the inheritance has to be established for both, the classes and the singleton classes:

MyClass     --->  #<Class:MyClass>
foo               bar
    ^                    ^
    |                    |
MySubClass  --->  #<Class:MySubClass>

Ruby optimized this internally – the singleton classes are only created when needed. But conceptually, this is what happens.

Apart from that, MyClass and MySubClass already come with some built-in class methods, most notably .new which is used to create instances, but also .superclass.

You might know that the default implementation of .new calls .allocate under the hood. So somewhere there must be a sort of "root class" which contains these methods. And since they are class methods, it must sit on top of the singleton class side:

                  <singleton root class>
                  new
                  allocate
                  superclass
                         ^
                         |
                        ...
                         |
MyClass     --->  #<Class:MyClass>
foo               bar
    ^                    ^
    |                    |
MySubClass  --->  #<Class:MySubClass>

And this mysterious top level singleton root class that provides the fundamental class methods for all other classes is ... Class!

Class.instance_methods(false)
#=> [:allocate, :superclass, :subclasses, :new]

CodePudding user response:

In general, the superclass of the singleton class of an object is the class of the object. I.e. for any object foo with a singleton class, the following holds:

foo.singleton_class.superclass == foo.class

However, for classes, this would be somewhat boring: the class of every class is Class, so the superclass of every class's singleton class would always be Class.

That is not particularly useful, since it would break some reasonable assumptions. For example, if I have something like this:

class Super
  def self.super_singleton_method; end
end

class Sub < Super; end

I would expect to be able to call Sub.super_singleton_method. However, in order to do this, Super.singleton_class needs to be somewhere in the method lookup chain of Sub.singleton_class.

So, for classes, the rule is somewhat different: the superclass of the singleton class of a class is the singleton class of the superclass of the class. I.e. for any class Foo, the following holds:

Foo.singleton_class.superclass == Foo.superclass.singleton_class

If you want, you can check whether this is true for every class in your system:

ObjectSpace.each_object(Class).select do |klass|
  klass.singleton_class.superclass != klass.superclass.singleton_class
end
#=> [BasicObject]

So, as you can see, this property does hold for all classes except BasicObject.

The simple answer for why BasicObject is different is that BasicObject has no superclass, and thus we cannot apply the rule. So, we fall back on the more general rule for all objects that

foo.singleton_class.superclass == foo.class

And BasicObject's class is Class, therefore,

BasicObject.singleton_class.superclass == BasicObject.class
BasicObject.singleton_class.superclass == Class

and also why no other object in ruby have the Class class as its superclass?

The only reason to inherit from Class would be to override the behavior of how inheritance or method lookup works in Ruby. But Ruby does not allow to override this. How inheritance and method lookup works is part of the language specification and cannot be changed. Therefore, inheriting from Class is illegal:

class MyClass < Class; end
# can't make subclass of Class (TypeError)

Thus there cannot be any object which has Class as its superclass, except singleton classes of classes. (Ruby can of course break its own rules since it is the one that makes the rules.)

How the logic behind the superclass of singleton_class of BasicObject is implemented in Ruby?

It isn't. You cannot explain how this works in Ruby, since it is part of the definition of Ruby itself.

It is similar to how Class is a subclass of Module, but Module is a class, i.e. an instance of Class. You cannot explain this from within Ruby using the rules of Ruby, but the Ruby implementation can, of course, set things up so that this works, since the Ruby implementation itself does not have to abide by the rules of Ruby: it is the one enforcing the rules, so it can just choose not to enforce them for itself.

  • Related