The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

Meta-Meta-Classes

... or How to twist your brain up in knots without even trying.

Note that the "Meta Meta Class" used in this document does not exist in the implemented language at all; more concretely, it is the encoding of the class model in the host language.

Introduction

This document is an ongoing attempt to clarify (and hopefully simplify) the all too hairy topic of MetaClasses and as a result provide a working basis for the Perl-6 Meta-Model. This may not be the correct nor is it the one and only way to view the concept of MetaClasses; many books have been written on the subject which all use subtly different concepts and terminology.

The Object Environment

Let us assume for a moment that all our object's live in an object environment (O), which is a finite set of objects, each of which is identified with a unique object reference.

Here is a diagram of the entire object environment:

  +-{Instance}-+ +--{Class}--+ +{MetaClass}+ +{MetaMetaClass}+
  |            | |           | |           | |               |
  |   ------   | |   -----   | |  -------  | |  -----------  |
  |  ( $foo )------>( Foo )----->( Class )---->( MetaClass ) |
  |   ------   | |   -----   | |  -------  | |  -----------  |
  |            | |           | |           | |               |
  +------------+ +-----------+ +-----------+ +---------------+

Our object environment has a set of rules which help to define the elements that exist within it.

However, before we do that, we must first make a point about the nomenclature found in the document.

Meta-Nomenclature

MetaClass systems are highly reflective by nature. This results in a very cyclical nomenclature, which at times can seem as if it is using itself to describe itself. Because of this we will try to be as consistent as possible in our nomenclature, and describe the "rules" of it here.

First, it needs to be noted that objects themselves are primative creatures in this environment. When we use the term object, we are refering to this primative element, and not the instance of a class.

When we write "type of XXX", we are moving upwards in the object environment (to the right on the above diagram); the type of an Instance is a Class, the type of a Class is a MetaClass, and the type of a MetaClass is a MetaMetaClass.

When we write "instance of XXX", we are moving downwards (or to the left in the diagram). An instance of a MetaMetaClass is a MetaClass, an instance of a MetaClass is a Class, and an instance of a Class is an Instance.

To stay on the same level, we use the term "XXX object".

There is also an important distinction between a noun "class", and a proper noun "Class". The proper noun "Class" refers specifically to the Class MetaClass, while "class" will refer to the class of which an object is an instance of (however in most cases we will use "type" here instead of class).

Rules of the object environment

Every Instance is an instance of some Class

These are the occupants of our environment O. Every noted Instance has a uniquely associated entity called a Class.

Every Class is an instance of a MetaClass

These objects are what would normally be described as your program's Model; ie, objects that are Classes will be called "Dog", "Tree", etc.

Every MetaClass is an instance of some MetaMetaClass

These objects are what would normally be described as your language Model, or program Meta-Model. These will be called "Class", "Role", etc.

Every MetaMetaClass is an instance of the underlying system

In theory, we could extend this relationship to any level. However, it simply does not make much sense to deal with these objects directly, they are the building block on which the above are created.

So what is a Meta-Meta-Class anyway?

Lets first define the other objects in our environment.

What is an object?

An object is a primative element in our environment. For the purposes of illustration we will use simple data-dictionaries/perl-ish hashes.

Here is an example of how an object describing a book might look like:

 {
    Book => { 
        'title'  => "VALIS",
        'author' => "Phillip K. Dick",
    }
 }

So what is an Instance?

An Instance is simply an object with a c<class> slot whose value is a reference to the class from which the instance is derived, and a set of instance variables (which are defined by the class (and which we will see later)).

So a iBook instance of the class Book would look like this:

 {
    'class' => Book
    Book => { 
        'title'  => "VALIS",
        'author' => "Phillip K. Dick",
    }
 }

So what is a Class?

A Class is itself just another data dictionary, however its structure is a bit more complex.

First, our class must have a name.

A class also needs to have a set of default instance variables from which new instances can be created.

Next, our class needs to have a method table, which is just another data dictionary whose keys are labels and whose values are code references. This table is seperate from the instance variables becuase methods remain in the class, and are not copied into the instance.

And lastly, we have inheritance. Our class needs to have parents, which we represent as an ordered list of other Class objects.

So given that, our Book class might be structured something like this:

 {
    'class' => Class,
    Class => {
        'name' => 'Book',
        'parents' => [ ... ],
        'instance_vars' => {
            Book => { title => '', author => '' }
        },
        'method_table' => {
            'get_author' => sub { ... },
            'set_author' => sub { ... },                    
            'get_title'  => sub { ... },
            'set_title'  => sub { ... },                                        
        }
    }
 }

As you can see, our Book class is itself an instance of the meta-class Class.

A list of supported instance variables and methods can be found by accumulating a properly sorted unique list of all a class's instance_vars and method_tables merged with those of its ancestors. These lists make it is possible to determine the instance variable and method resolution order.

So what is a MetaClass?

Once again, we can represent our meta-class as a data dictionary. Here is an example of how the meta-class Class would look:

 {
    'class' => MetaClass,
    MetaClass => {
        'name' => 'Class',
        'parents' => [ ... ],
        'instance_vars' => {
            Class => { 
                'name'          => "",
                'parents'       => [],
                'instance_vars' => {},
                'method_table'  => {}
            }
        },
        'method_table' => {
            'create_instance' => sub { 
                return { 'class' => Class, Class.<instance_vars> }
            }
        }
    }
 }

The instance_vars for a Class are basically those of an empty parent-less class, nothing more, nothing less. The simplicity of this notion can be somewhat difficult to swallow. The tempation is to make it seem much more complex, but in reality it is not.

We also take this opportunity to define a create_instance method for our MetaClass which basically just creates a new data dictionary, adding the required 'class' key and value pair, along with a copy of the instance_vars. Again, it need not be any more complex than that.

So what is a MetaMetaClass?

Now we are back to our original question, and hopefully by now the answer is quite obvious.

A MetaMetaClass is simply a concrete implementation of the data structures we have been constructing above. Our MetaMetaClass is the root of our object hierarchy, and the object from which all others can be defined.

"That's all?" you say. "But it can't possibly be all!".

It is of course important to keep a few things in mind, the first of which is that this MetaMetaClass is actually independent of a given programming language. That it is not something which the "user" should ever really have access too. It is a part of the compiler and/or runtime environment upon which a programming language resides.

The second thing is ... hmmm, what was it??

Why do we need all this abstraction?

What follows is a (slightly edited) snippet of a converstation which took place on IRC.

    <gaal>          why do we need one more level after classes?
    <gaal>          and how come just one more level is enough?
    <gaal>          what do you do with that? that kind of stuff
    <stevan>    well, there is not a really a quick answer
    <stevan>    but I will try :)
    <stevan>    basically it is this
    <stevan>    a class needs to be something
    <stevan>    an instance of something that is
    <stevan>    because there are more than one class in any system
    <gaal>          why not an object, like in java?
    <stevan>    well the Object type in Java is sort of like a metaclass
    <gaal>          okay
    <stevan>    it is the base from which all things are derived
    <stevan>    just automagically
    <gaal>          yes, i see that.
    <stevan>    the heirarchy must come to a point/root
    <stevan>    in Java it is the Object
    <stevan>    in Smalltalk it is MetaClass (i think)
    <stevan>    take a theoretical object model 
    <gaal>          uh huh
    <stevan>    where we have basic Classes
    <stevan>    which have methods and properties
    <stevan>    say you want to add Final classes
    <stevan>    like Java
    <stevan>    how would you do that?
    <stevan>    subclass Class of course
    <stevan>    but this means that Class itself must be an instance of something 
    <gaal>          okay, yes
    <stevan>    remember too that this is not something the "user" of the language ever sees
    <gaal>          yup
    <gaal>          that was clear enough from your explanation
    <stevan>    so you can subclass Class and get FinalClass
    <stevan>    so this brings up the question, what is Class an instance of
    <stevan>    MetaClass
    <stevan>    so you can stop your model at MetaClass
    <stevan>    and say that is the root
    <stevan>    OR
    <stevan>    you can go one level higher
    <stevan>    which then makes it easier to have Roles, Classes, Traits, etc.
    <stevan>    the MetaMetaClass is the root now, and each MetaClass is an instance of it
    <stevan>    some of the MetaClasses in Perl6 will be Role, Class
    <stevan>    mugwump also included Module and Package too
    <gaal>          the perl code in ext/, is it part of the actual implementation of oop in pugs?
    <stevan>    no
    <gaal>          has autrijus assimilated that into the haskell code?    
    <stevan>    right now it is just a prototype to play around with an object model
    <gaal>          ah, okay
    <stevan>    he might eventually do that
    <stevan>    if it works out
    <gaal>          i see. this is cool stuff.    
    <stevan>    but it is easier to prototype in perl (5|6) then it is in Haskell (at least for me)
    <gaal>          yeah, me too.
    <stevan>    meta-meta-hacking :)
    <stevan>    basically you are modeling the class/object system
    <gaal>          yes, i get that. i think java is a big help here because it's so consistent
    <stevan>    I will try to update the meta-meta doc later today
    <gaal>          okay thanks for the brief.
    <stevan>    np

I always find that the best way to explain things is to use examples. So for an example of how one might use meta-classes (not meta-meta-classes), please see the create_your_own_object_model.pod document in the folder as this document.

ACKNOWLEDGEMENTS

Much of what is found in this document is a direct rip-off of the contents of the first few chapter of this book (defined here as an instance of a Book class):

 {
    'class' => Book,
    Book => {
        'title'     => "Putting Metaclasses to Work",
        'authors'   => [ 'Ira R. Forman', 'Scott H. Danforth' ],
        'publisher' => 'Addison-Wesley'
        'isbn'      => 0-201-43305-2,
    }
 }

However, despite my plagarism/summariazation, I still take responsibility for all errors, inconsistencies or outright lies this document might contain.

AUTHORS

Stevan Little <stevan@iinteractive.com>

Sam Vilain <samv@cpan.org>