++ed by:
TOBYINK ROMANF MHOWARD

3 PAUSE users
4 non-PAUSE users.

Rodolphe Ortalo

NAME

MOP::MOP - Perl extension providing a meta-object protocol for Perl modules.

SYNOPSIS

    # A random package declaration
    package MyBaseModule;

    # Activate the meta-object protocol for a few methods
    use MOP::MOP qw(new method1 method3);
    # Our meta-module is 'MyMetaModule'
    MOP::MOP::register_meta('MyMetaModule','MyBaseModule');

    # Some functions
    sub new () {
        return bless {};
    }
    sub method1 ($$) { ... }
    sub method2 ($) { ... }
    sub method3 () { ... }

DESCRIPTION

This module provides a simple and, in my opinion, powerful meta-object protocol (MOP) for Perl5 modules. In short, such MOP allows to trap the method calls made on an object (represented by a reference) before they reach the original module implementing them. These method calls are redirected to another module, called the meta-module, before their execution. The original (legitimate) destination of the method call is in the (base) module. Of course, one day or another, the meta-module should perform the actual normal method call at the base level, but it can do some nice things before or after doing that. And this is the whole purpose of its existence.

MOP::MOP implements the base level part of the protocol. This module is tightly linked with module MOP::MetaModule which implements the other upper part of the behavior, i.e. the generic behavior of a meta-module.

In the above example, MyBaseModule is the base module, and MyMetaModule is the meta-module (not shown here). In this example, the 3 methods new(), method1() and method3() are modified due to the MOP. These methods become reflective methods. When a user of MyBaseModule calls one of these methods, they are not called directly, but the method meta_method_call() of MyMetaModule is called instead. This method is passed the original arguments of the method call, prepended by the (base level) method name and (base level) object reference or package name used.

Hence, if a programmer does:

    use MyBaseModule;
    my $obj = MyBaseModule->new($newarg);
    $obj->method1($foo, $bar);
    $obj->method2($bur);
    $obj->method3();

In fact, the actual operations taking place correspond to the following steps.

  1. $obj = MyMetaModule->meta_method_call(new_Refl, 'MyBaseModule', $newarg)

    This occurs in place of the first call, as MyMetaModule is registered as the meta-module of MyBaseModule.

Then, supposing that at the end of this strange new() a meta-object referenced by $metaobj is registered for the freshly created $obj, the processing will continue as in the following.

2.

$metaobj->meta_method_call(method1_Refl, $obj, $foo, $bar)

This is the call of a reflective method on $obj and such calls are processed by the meta-object, not by perl itself directly (even though Perl behavior remains valid somewhere else).

3.

$obj->method2($bur)

This is a normal method call. As method2() is not reflective, the work is done by perl itself.

4.

$metaobj->meta_method_call(method2_Refl, $obj)

Again, a reflective method call to finish.

Note: Here, even if they are actually used, the blabla_Refl names are only for illustration. They represent the name of the base level method. The meta-object needs them if it ever wants the real work to be done. But note that the structure of these names may not follow this scheme indefinitely (and these thingies may become code references in the future). See meta_handle_method_call() in MOP::MetaModule.

A MOP is mainly useful for modules that provide a rather strict object-oriented interface. It allows to extend transparently the functionality provided by such a class module in order to provide additional properties not directly related to the module functions. This may sound rather obscure, but it can really be useful. For example, this is the case in the real world when you want to add transparent distribution to your programs, when you want to enhance such distributed execution with a CRC integrity check in messages, when you want to manage multiple replicas of a server, etc.

Functions

MOP::MOP::register_meta($metaobj,$obj)

Registers the object $metaobj as the meta-object of the (base) object $obj. This allows the MOP to find which meta-object is associated to a given object (the meta-level often needs a state, stored in the meta-object). You can also directly associate a meta-module to a module. This is even necessary to bootstrap the protocol somewhere.

MOP::MOP::find_meta($obj)

Finds the meta-object associated to $obj. It is usually not needed to call this function directly as the MOP itself provides the base level object to the meta-object among the arguments to meta_method_call().

Is it possible to do something useful with this?

The test programs included with the distribution of this module demonstrate such usage (and I hope that the number of really useful meta-modules will increase as time goes and files migrate from t/ to their own subdirectory). Most simple examples deal with not very useful meta-modules, such as counting the number of method calls, tracing some method calls, etc.

More serious examples include a full-featured client/server system that should allow to execute any Perl object remotely without modifying the source code of the original module. The MOP traps the creation and local method calls on the object (which remains an empty proxy on the client side). The meta-module takes care of redirecting all calls and calling the real object on the server. See module MOP::Remote. Note that you need the Data::Dumper module to run that test. Currently, it is blindly based on the availability of the Unix rsh command. But I've been seriously using this mechanism for distributed processing for more than one year up to now.

A future demo program that will be added soon will show how to add some (simple) encryption to that remote execution system. The idea is simply to encrypt transparently the data exchanged by the client/server meta-objects, using another meta-object. Thus introducing to the world a meta meta-module.

Notes

The MOP::MOP module is implemented as a source filter and is dependent on the Filter::Util::Call module.

This module transparently modifies the source code of your module. It really renames the method subroutines and replaces them by stubs. Be warned that we are somehow redefining the world...

Would it be possible to keep the module source code somewhere in memory and track the uses of libraries thanks to this mechanism? It could be nice to enable Perl to send all this to another host...

BUGS

Functions stubs (e.g.: sub truc;) probably do not work.

This documentation is much bigger than the module code itself. Do not hesitate to read the source code!

AUTHOR

Rodolphe Ortalo, ortalo@laas.fr

Acknowledgements

This work has been performed with the support of LAAS-CNRS.

SEE ALSO

perl(1), MOP::MetaModule(3), MOP::Remote(3), Filter::Util::Call(3).

2 POD Errors

The following errors were encountered while parsing the POD:

Around line 187:

Expected text after =item, not a number

Around line 194:

Expected text after =item, not a number