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

=head1 Create Your Own Object Model

So all this meta-meta-stuff can be interesting, but the real question is: How
does it fit into a real-world scenario? I mean, what do you do with all this
abstraction?

Why make your own object model of course :)

=head2 Designing your object model

First we need to decide what to put into our object model. Now since this is
an example for illustrative purposes, I will try to keep it simple. However, 
I think you will be surprised to see how easy it is to make robust object model
using meta-classes.

So obviously we will have I<classes> in our model. For the purposes of our 
example, we will define a class as simply a collection of properties and methods, 
and we won't bother about public/private or any such things.

We will also add I<abstract classes> to our model. We will define an abstract 
class as being a class with no instance variables, and whose method labels 
are defined, but are not implemented. This is a very simplistic definition of 
abstract classes, but it should suffice for this example.

The last item we will add to our object model are I<thread safe> classes. These
are classes which will be guaranteed to be thread safe. And despite what you might 
think, this one is actually very simple to implement.

Now with our object model defined, let's build it.

=head2 Building your object model

First we determine the structure of our meta-class hierarchy. In my mind, abstract 
classes should be our base meta-class; with regular classes being a subclass of 
abstract classes; and finally the thread safe classes being a subclass of our classes.

First we define our B<AbstractClass> meta-class:

 {
    'class' => MetaClass,
    MetaClass => {
        'name' => 'AbstractClass',
        'parent' => undef,
        'instance_vars' => {
            AbstractClass => { 
                'name'          => "",
                'parents'       => [],
                'method_table'  => {}
            }
        },
        'method_table' => {
            'create_instance' => { 
                die "You cannot instantiate an AbstractClass";
            },
            'add_method_to_class' => ($class, $label) -> {
                $class.<method_table>.<$label> = \&abstractMethodHandler;
            },
            ...
        }
    }
 }

An B<AbstractClass> does not have a C<instance_var> slot since they are not allowed.
We also implement a C<add_method_to_class> method in our B<AbstractClass> method table 
which will allow us to easily enforce the fact that all our methods use the same 
C<\&abstractMethodHandler> (which will throw an appropriate error if called). We also 
throw an error with the C<create_instance> method since B<AbstractClasses> can be 
instantiated.

Next we define the B<Class> meta-class (which is actually a subclass of the 
B<AbstractClass> meta-class):

 {
    'class' => MetaClass,
    MetaClass => {
        'name' => 'Class',
        'parent' => AbstractClass,
        'instance_vars' => {
            Class => { 
                'instance_var' => {}
            }
        },
        'method_table' => {
            'create_instance' => { 
                return merge(
                    Class.parent.<instance_vars>,
                    { 'class' => Class, Class.<instance_vars> }
                ); 
            },
            'add_method_to_class' => ($class: $label, $impl) -> {
                $class<method_table><$label> = $impl;
            },
            ...
        }
    }
 }

Notice the C<parent> slot, which points back to the B<AbstractClass> meta-class. We
also now include an C<instance_var> slot into the B<Class> meta-class's C<instance_var> 
slot, all the other slots are defined in B<AbstractClass>. This allows our B<Class> 
meta-class to have instance variables, which we denied to our B<AbstractClass> meta-class.

Next is the C<create_instance> meta-class method which merges the C<instance_vars> of 
the parent (B<AbstractClass>) with the C<instance_vars> of the B<Class>, and of course our 
C<add_method_to_class> meta-class method now accepts a method implementation (C<$impl>).

Okay, so now we have a basic object model here. We have abstract classes as well as 
regular basic everyday classes. Simple, right? :)

Now comes our last meta-class, the B<ThreadSafeClass>. 

For the purposes of my example, I am keeping it very simple and saying that in 
order to be thread safe, every method must acquire an instance specific C<semaphore>
prior to executing, and then release that C<semaphore> after execution. 

Here is what that would look like:

 {
    'class' => MetaClass,
    MetaClass => {
        'name' => 'ThreadSafeClass',
        'parent' => Class,
        'instance_vars' => {
            'semaphore' => <semaphore>
        },
        'method_table' => {
            'add_method_to_class' => ($class: $label, $impl) -> {
                $class<method_table><$label> = ($self: @args) {
                    $self<semaphore>.acquire();
                    @return_vals =
		    $self.invoke_method($impl, @args);
                    $self<semaphore>.release();                        
                    return @return_vals;
                }
            },
            ...
        }
    }
 }

This is somewhat of a simplistic implementation, but it serves to illustrate the 
power of meta-classes quite well. We need to add the C<semaphore> C<instance_var>
slot since all our instances will need one. And then in the C<add_method_to_class>, 
we simply wrap the method in our own thread-safe wrapper.

So as you can see, using meta-classes we can very easily create fairly robust 
object models quite simply. 

[... more to come later ...]

=head1 AUTHOR

Stevan Little E<lt>stevan@iinteractive.comE<gt>

=cut