The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

Perl 6 Meta Meta Class Hierarchy

This document attempts to explain the Meta-Meta-Class hierarchy and implementation.

       .............> MetaClass <...............
       :                 |                     :         ---> isSubclassOf
       :                 |                     :         ...> isInstanceOf             
       :                 V                     :         - -> does()
       :          Class::Behavior<----------+  :
       :                 |                  |  :
       :                 |                  |  :       
       :                 V                  |  :       
       :  +------> Role::Behavior           |  :                                  
       :  |              |                  |  :
 metaclass(Role)         |      ..... > metaclass(Class)
       ^                 V      : 
       :              Object    :
       :                 |      :
       :                 |      : 
       :                 V      :
      Role < - - - - - Class ...   
   
 
 role Role {}
 class Class does Role {}  
 
 class Object is Class {}
 class Role::Behavior is Object {}
 class Class::Behavior is Role::Behavior {} 
 class MetaClass is Class::Behavior {}  
 
 my $Role = MetaClass.new('Role');
 $Role.superclass(Role::Behavior); 
 
 my $Class = MetaClass.new('Class'); 
 $Class.superclass(Class::Behavior);
 $Class.roles($Role);
 

Or a sligthly different view of the same:

 +--{ Implementation Layer }--------------------+
 |                                              |  ---> isSubclassOf
 |   +----------->Role::Behavior                |  ...> isInstanceOf
 |   |                  ^                       |  - -> does()
 |   |                  |                       |
 |   |           Class::Behavior<-----------+   |
 |   |                  ^                   |   |
 +---|------------------|-------------------|---+
 |   |                  |                   |   |
 |   |                  |                   |   |
 |  Role .........> MetaClass <.......... Class |
 |   ^                                      |   |                
 |   + - - - - - - - - - - - - - - - - - - -+   |
 |                                              |
 +---------------{ Meta Space }-----------------+

A Note about Roles

Roles are not and do not inherit.

A Role is flattened into either a Class or another Role. This act of flattening negates any real "hierarchy" like that of a Class hierarchy.

This is an important distinction to remember.

A Note about Duck-Typing

Duck typing is usually described like this:

  If it quacks like a duck, it must be a duck.

Which basically means that a Type is defined by the methods it responds to, instead of some label it has been given. However, this is a very simple defintion of duck-typing from the users point of view, and fails to explain it from the implementation point of view.

From the implementation point-of-view, duck-typing means that instead of an object's behavior being defined by a class, it is defined by a Type entity which exists in the somewhat muddy area between Class and Instances.

  [ Class + [ Role, ... ]] --> ::Type <--- Instances

A class and it's attached roles are "compiled" into a Type, which is then used by instances in the system.

Implementation Layer

The behavior of classes and roles must be described somehow, and we should be able to re-use that implementation as well.

I propose a Class::Behavior and Role::Behavior implementation.

A Role::Behavior has a hash of methods and a hash of properties, as well as an array of Roles. Role::Behavior encapsulates all of the behavior needed to compose a Role.

A Class::Behavior is a subclass of Role::Behavior because a class also has a hash of methods and properties and an array of roles. It then adds to that with a parent class as well as a set of subclasses. Class::Behavior encapsulates all of the behavior needed to compose a Class.

Meta Space

The Meta Space contains all of our meta-objects of which I see 3 distinct types.

MetaClass

This is the "root" of our MetaClass hierarchy, and the loopback point of our object model. It is a subclass of Class::Behavior.

Role

The Role is itself an instance of the MetaClass, but it is also a subclass of the Role::Behavior.

Class

The Class too is an instance of the MetaClass, and it is a subclass of Class::Behavior.

The Class also does() the role Role.

NOTE: this Class.does(Role) relationship may not be needed, but I am leaving it in for now.

Rough Code Sketches

Conventions

"metaclass(Foo)" means the instance of MetaClass with the name of Foo
"class(Foo)" means the instance of Class with the name of Foo

metametaclass(MetaClass)

    metametaclass MetaClass is Class::Behavior {
        has $.name;   
        has @:roles;   
        has $:superclass;
        has @:subclasses;            
        has %.properties;
        has %.methods;   
        
        method addProperties {}
        method addMethods {} 
        method invokeMethod {}
        method super { ... } # a class must be able to inherit from another class
        method subclasses { ... } # a class must be able to be inherited from        
        method doesRole {} # doing a Role just folds properties and methods into the metaclass
    }
    
    my $Role = MetaClass.new('Role'); # metaclass(Role) is an instance of metametaclass(MetaClass)
    $Role.superclass(Role::Behavior); 
    $Role.addProperties(
        $.name,
        @:roles,
        %:properties,
        %:methods
    );
    $Role.addMethods(
        roles
    );
    
    # Hmmm,... MetaClass and Role look suspiciously similar
    
    my $Class = MetaClass.new('Class'); # metaclass(Class) is an instance of metametaclass(MetaClass)    
    $Class.superclass(Class::Behavior); 
    $Class.doesRole($Role);
    $Class.addProperties(
        $:superclass,
        @:subclasses
    );
    $Class.addMethods(
        super,
        subclasses,
        invokeMethod 
    );

metaclass(Role)

When "compiled" the metaclass(Role) will look something like this:

    metaclass Role is Role::Behavior {
        has $.name;
        has @.roles;
        has %.properties;
        has %.methods;

        method roles { ... } # a role must be able to attach other roles to it
        # property access is made possible through methods
    }

NOTE: In order for the metaclass(Role) to be able to compose more roles, it must have all the methods of a Role::Behavior. Since we don't want these methods to actually be inherited down to the next level (the "user" space), we make the metaclass inherit from Role::Behavior in the implementation itself, and not as a superclass(). The same is done for metaclass(Class) and Class::Behavior.

    my $bar_role = Role.new('Bar'); # role(Bar) is an instance of metaclass(Role)
    $bar_role.addProperties(
        $.baz
    );
    $bar_role.addMethods(
        baz
    );
    

Can then be "compiled" into this role(Bar):

    role Bar {
        has $.baz;
        method baz { ... }
    }

metaclass(Class)

When "compiled" the metaclass(Class) will look like this:

    metaclass Class is Class::Behavior does metaclass(Role) {
    
        # the following properties are from metaclass(Role)
        #   $.name, @.roles, %.properties, %.methods;
        # the following methods too
        #   roles(), invokeMethod()
    
        has @.superclasses;
        has @.subclasses;

        method super { ... } # a class must be able to inherit from another class
        method subclasses { ... } # a class must be able to be inherited from
        method invokeMethod { ... }
    }

    my $foo_class = Class.new('Foo'); # class(Foo) is an instance of metaclass(Class) 
    $foo_class.doesRole('Bar');
    $foo_class.addProperties(
        $.foo
    );
    $foo_class.addMethods(
        foo
    );
    

This can then be compiled into this class(Foo):

    class Foo {
        has $.foo;
        has $.baz;
        method foo { ... }
        method baz { ... }
    }
      

AUTHORS

Stevan Little <stevan@iinteractive.com>