Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby metaclass confusion

Tags:

metaclass

ruby

I understand that all classes in ruby are instances of metaclass Class. And that "regular" objects are instances of these classes (the instances of metaclass Class).

But I keep wondering, I mean classes are root of objects, classes are themselves instances of Class (called metaclass because its instances are classes). I saw in some blogs some overriding of method new, of class Class.

So Class behaves as a class, but its instances are classes. So it seems we have a circle, it looks likes class Class is an instance of itself.

I'm clearly missing a point here. What is the origin of class Class?

Here's an example that's confusing me:

class Class
  def new
    #something
  end
end

But keyword class implies an instance of class Class. So how do this work?

like image 983
Perello Avatar asked May 09 '12 22:05

Perello


People also ask

What is metaclass in Ruby?

When you declare a singleton method on an object, Ruby automatically creates a class to hold just that method. This class is called the 'metaclass' of the object. All subsequent singleton methods of this object goes to its metaclass.

What is metaclass in OOP?

In object-oriented programming, a metaclass is a class whose instances are classes. Just as an ordinary class defines the behavior of certain objects, a metaclass defines the behavior of certain classes and their instances. Not all object-oriented programming languages support metaclasses.

What is metaclass in Java?

A MetaClass describes a real Class with the purpose of providing to an IDE class level information, and delaying the loading of that class to the last possible moment: when an instance of the class is required. A MetaClass binds the Class object from its class name using the appropriate class loader.

Does Java have metaclass?

In Java there's a single metaclass: the instances of the class Class are used to represent the types of classes and interfaces.


2 Answers

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.

like image 113
Jörg W Mittag Avatar answered Oct 03 '22 17:10

Jörg W Mittag


There is a meta-circularity given by the "twist" link. It is the built-in superclass link from the root's eigenclass to the Class class. This can be expressed by

BasicObject.singleton_class.superclass == Class

A clue to understanding the .class map is seeing this map as derived from the eigenclass and superclass links: for an object x, x.class is the first class in the superclass chain of x's eigenclass. This can be expressed by

x.class == x.eigenclass.superclass(n)

where eigenclass is a "conceptual alias" of singleton_class (resistant to issues with immediate values), y.superclass(i) means i-th superclass of y and n is smallest such that x.eigenclass.superclass(n) is a class. Equivalently, eigenclasses in the superclass chain of x.eigenclass are skipped (see rb_class_real which also reveals that in MRI, even superclass links are implemented indirectly – they arise by skipping "iclasses"). This results in that the class of every class (as well as of every eigenclass) is constantly the Class class.

A picture is provided by this diagram.

The metaclass confusion has 2 main sources:

  • Smalltalk. The Smalltalk-80 object model contains conceptual inconsistencies that are rectified by the Ruby object model. In addition, Smalltalk literature uses dialectics in terminology, which unfortunately has not been sufficiently remedied in the Ruby literature.

  • The definition of metaclass. At present, the definition states that metaclasses are classes of classes. However, for so called "implicit metaclasses" (the case of Ruby and Smalltalk-80) a much more fitting definition would be that of meta-objects of classes.

like image 28
paon Avatar answered Oct 03 '22 19:10

paon