Day 22 – The Meta-Object Protocol

by

Have you ever wondered how to create a class in your favorite programming language, not by writing a class definition, but by running some code? Some languages allow that by simple API calls. The API behind it is called the Meta-Object Protocol, short MOP.

Perl 6 has a MOP, and it allows you to create classes, roles and grammars, add methods and attributes, and to introspect classes. For example we can use calls to the MOP in Rakudo to find out how the Rat type (rational numbers) is implemented. Calls to methods of the MOP generally start with .^ instead of just .:

 $ perl6
 > say join ', ', Rat.^attributes
 $!numerator, $!denominator
 > # the list of all methods is a bit long,
 > # so here is a random selection
 > say join ', ', Rat.^methods(:local).pick(5)
 unpolar, ceiling, reals, Str, round
 > say Rat.^methods(:local).grep('log').[0].signature.perl
 :(Numeric $x: Numeric $base = { ... };; *%_)

Most of these lines should be fairly self-explanatory: objects of class Rat has two attributes, $!numerator and $!denominator, as well as many methods. The log method takes a Numeric value as invocant (marked by the colon after the parameter name), and an optional second parameter called $base, which has a default value (but which Rakudo can’t show you. It’s Euler’s number).

A nice use case comes from the Perl 6 database interface. It has the option to log calls on an object, and to restrict this to only log methods from a certain role (for example only a role related to connection management, or related to data retrieval). Here is the example, and a possible way to call it:

 sub log-calls($obj, Role $r) {
     my $wrapper = RoleHOW.new;
     for $r.^methods -> $m {
         $wrapper.^add_method($m.name, method (|$c) {
             # print logging information
             # note() writes to standard error
             note ">> $m";
             # call the next method of the same name,
             # with the same arguments
             nextsame;
         });
     }
     $wrapper.^compose();
     # the 'does' operator works just like 'but', but
     # only modifies a copy of the object
     $obj does $wrapper;
 }
 role Greet {
     method greet($x) {
         say "hello, $x";
     }
 }
 class SomeGreeter does Greet {
     method LOLGREET($x) {
         say "OH HAI "~ uc $x;
     }
 }
 my $o = log-calls(SomeGreeter.new, Greet);
 # logged, since provided by role Greet
 $o.greet('you');
 # not logged, because not provided by the role
 $o.LOLGREET('u');

Output:

 >> greet
 hello, you
 OH HAI U

So with a Meta-Object Protocol, classes, roles and grammars are not just accessible by special syntax, but can be accessed as a normal API. This gives new flexibility to object oriented code, and allows easy introspection and modification of objects.

About these ads

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


Follow

Get every new post delivered to your Inbox.

Join 43 other followers

%d bloggers like this: