Can Someone Explain the Class.Superclass.Class.Superclass Paradox

Can someone explain the Class.superclass.class.superclass paradox?

TL;DR: Module is the superclass of Class. Module is an instance of Class.


Let me try to explain it more clearly. Please forgive my handwritten drawings - I don't have any fancy drawing software.

Every class in Ruby has 1 superclass*.

Sample Image

*Except for BasicObject, which doesn't have a superclass.

Read the above graphic like this: The superclass of Float is Numeric. The superclass of Numeric is Object, etc...

When you instantiate an object, the object will be an instance of some class. For example, "Nathan" is an instance of the String class. So is "Joe" or "John". 1 is an instance of the Fixnum class, as are 2, 3, 4, etc...

Sample Image

Read the above graphic like this: "Joe" is an instance of String. 1 is an instance of Fixnum, etc...

Well, in Ruby, unlike in most other languages, Class is a just another class, and it can be instantiated, too, just like Fixnum or String.

Sample Image

Read the above graphic like this: 0.01 is an instance of Float. String is an instance of Class, etc...

Realize that Fixnum is an instance of Class, just like "Nathan" is an instance of String. Just like "John" is an instance of String, Float is just an instance of Class. Every class is just an an instance of Class, even Class itself!

Whenever you write a new class in your app, you are just instantiating a new object whose class is Class, just like Hash.new instantiates a new Hash, or "Nathan" instantiates a new String.

# By running this, you will be instantiating a new Class, and 
# it will be named Post
class Post < ActiveRecord::Base
end

# Here is another perfectly valid way to write the above code:
Post = Class.new(ActiveRecord::Base)

# you can even instantiate a Class without giving it an explicit name:
x = Class.new(ActiveRecord::Base)

# and since your new things are classes, they can be instantiated
obj1 = Post.new
obj2 = x.new

Furthermore, Module is just another instance of Class. Whenever you write a new module in your app, you are just instantiating a new Module.

# this will instantiate a new Module, and assign it to Foo
module Foo
end

# Here is another perfectly valid way to write the above code:
Foo = Module.new

# you can even instantiate a Module without giving it an explicit name.
m = Module.new

An aside: A Module is just a collection of methods and constants. Classes are also a collection of methods and constants, but with the added functionality of being able to be instantiated. A module cannot be instantiated. That is, m.new will not work.

So, referring back to the top graphic, your question can be answered directly:

So a class's parent is module, but module is a class?

You can see from the top graphic: Module is the superclass of Class.

From the bottom graphic: Module is an instance of Class.

The Class/Object Paradox confusion

You can see the problem in this diagram:

Ruby Method Lookup Flow

(source: phrogz.net)

All object instances inherit from Object. All classes are objects, and Class is a class, therefore Class is an object. However, object instances inherit from their class, and Object is an instance of the Class class, therefore Object itself gets methods from Class.

As you can see in the diagram, however, there isn't a circular lookup loop, because there are two different inheritance 'parts' to every class: the instance methods and the 'class' methods. In the end, the lookup path is sane.

N.B.: This diagram reflects Ruby 1.8, and thus does not include the core BasicObject class introduced in Ruby 1.9.

Ruby metaclass confusion

how do this work

Easy: it doesn't. Not in Ruby, anyway.

Just like in most other languages, there are some core entities that are simply assumed to exist. They fall from the sky, materialize out of thin air, magically appear.

In Ruby, some of those magic things are:

  • Object doesn't have a superclass, but you cannot define a class with no superclass, the implicit direct superclass is always Object. [Note: there may be implementation-defined superclasses of Object, but eventually, there will be one which doesn't have a superclass.]
  • Object is an instance of Class, which is a subclass of Object (which means that indirectly Object is an instance of Object itself)
  • Class is a subclass of Module, which is an instance of Class
  • Class is an instance of Class

None of these things can be explained in Ruby.

BasicObject, Object, Module and Class all need to spring into existence at the same time because they have circular dependencies.

Just because this relationship cannot be expressed in Ruby code, doesn't mean the Ruby Language Specification can't say it has to be so. It's up to the implementor to figure out a way to do this. After all, the Ruby implementation has a level of access to the objects that you as a programmer don't have.

For example, the Ruby implementation could first create BasicObject, setting both its superclass pointer and its class pointer to null.

Then, it creates Object, setting its superclass pointer to BasicObject and its class pointer to null.

Next, it creates Module, setting its superclass pointer to Object and its class pointer to null.

Lastly, it creates Class, setting its superclass pointer to Module and its class pointer to null.

Now, we can overwrite BasicObject's, Object's, Module's, and Class's class pointer to point to Class, and we're done.

This is easy to do from outside the system, it just looks weird from the inside.

Once they do exist, however, it is perfectly possible to implement most of their behavior in plain Ruby. You only need very barebones versions of those classes, thanks to Ruby's open classes, you can add any missing functionality at a later time.

In your example, the class Class is not creating a new class named Class, it is reopening the existing class Class, which was given to us by the runtime environment.

So, it is perfectly possible to explain the default behavior of Class#new in plain Ruby:

class Class
def new(*args, &block)
obj = allocate # another magic thing that cannot be explained in Ruby
obj.initialize(*args, &block)
return obj
end
end

[Note: actually, initialize is private, so you need to use obj.send(:initialize, *args, &block) to circumvent the access restriction.]

BTW: Class#allocate is another one of those magic things. It allocates a new empty object in Ruby's object space, which is something that cannot be done in Ruby. So, Class#allocate is something that has to be provided by the runtime system as well.

What does this Ruby syntax mean: if self Class::Name?

It checks if self is a subclass of Example::Class::Name

Check out the Module docs :)

Can someone help explain the post_initialize callback for class creation (Sandi Metz)

The important thing to understand here is that in this code:

def initialize(args = {})
# ...
post_initialize(args)
end

...post_initialize has an implicit receiver, self. In other words, post_initialize(args) here is equivalent to self.post_initialize(args), and self is an instance of MountainBike. Method lookup always starts with the receiver's class, so it has no trouble finding MountainBike#post_initialize.

 That's a lie; it's not equivalent when it comes to privacy; private methods cannot be called with an explicit receiver.

 That's also a lie; it actually starts with the receiver's singleton class, but then it tries its class.

Every class is implicitly a subclass of Object Java

Meaning of implicitly - suggested though not directly expressed.

If samething applied in Java classes. Consider there is a class called Test.

If you write

public class Test {....}

That is equivalent to

  public class Test extends Object {....} 

Though you didn't write it, it's equivalent to it. You need not to write extends Object manually. Internally JVM treats that your class is extends Object. Since the part after extends is your class, here Object is your super class.

But,

When you write

  public class Test extends BigTest{....} 

Things changed now. You are telling BigTest is my parent class. That means you are implicitly writing yourself that BigTest is my parent. Interesting part here is though BigTest is your direct Parent class, internally Object also your Parent.

So now you have 2 parent classes. One is BigTest which you mentioned and other is Object. If you didn't mention anything, only Object is your Parent.

Edit :

This is the reason that you will see extra list of method when you will try to call any member of class with object-reference. Those methods are declared in Object class.

why java do this? any feature of this?

Yes. There are benefits of it. Main reason is to reduce the code duplication.

Continue reading here .... Why Object as super class in Java ?

Inheritance in java and Superclasses(Object, Class)

Everything is an Object, that said you could see the structure as this:

Object

Animal

Cat

and not as this:

Object    Animal

Cat

Where Cat extends both, it's not like this last example, but it's Cat that extends Animal which extends Object.



Related Topics



Leave a reply



Submit