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.