Skip to content

Anyone for metaprogramming?

January 13, 2010

What is metaprogramming? Well this question caused a heated discussion on Hacker News yesterday.

I personally would describe that metaprogramming provides the ability to:

transform programs with programs

and leave it at that!

The article that stirred the metaprogramming pot was Metaprogramming: Ruby vs. Javascript. This actually is a good post and it helped fill in a few holes in my “fragile” Javascript knowledge.

Luckily I believe my Perl is a bit less fragile!, so I thought I would convert the metaprogramming examples into Perl & Moose.

So following the blogs examples, below defines the Ninja class in Moose. MooseX::SingletonMethod loads Moose with a bit of singleton method sugar.

use Modern::Perl;

{
    package Ninja;
    use MooseX::SingletonMethod;
    use namespace::clean -except => 'meta';
    
    has name => ( is => 'rw', isa => 'Str' );
}

my $drew = Ninja->new( name => 'Drew' );
my $adam = Ninja->new( name => 'Adam' );

NB. namespace::clean stops the Moose sugar percolating into Ninja class (except meta… which is the Meta Object Protocol method… which handy for metaprogramming!).

Now we re-open the Ninja class and add battle_cry method like so:

{
    package Ninja;
    
    sub battle_cry {
        my $self = shift;
        say $self->name . ' says zing!!!'; 
    }
}

$drew->battle_cry;   # => Drew says zing!!!
$adam->battle_cry;   # => Adam says zing!!!

Now using MooseX::SingletonMethod we add throw_star singleton method into $drew object:

$drew->add_singleton_method( throw_star => sub {
    say "throwing star";
});

$drew->throw_star;   # => throwing a star

To call method dynamically we do this:

$drew->${ \'battle_cry' };   # => Drew says zing!!!

Create colour method closing over $colour_name (ie. closure):

my $colour_name = 'black';

Ninja->meta->add_method( colour => sub {
    my $self = shift;
    say "${ \$self->name }'s colour is $colour_name";
});

$drew->colour;    # => Drew's colour is black
$adam->colour;    # => Adam's colour is black

Finally… “defining a method dynamically on an instance that closes over local scope and accesses the instance’s state”

my $sword_symbol = '********';

$drew->add_singleton_method( swing => sub {
    my ($self, $sound_effect) = @_;
    say "${ \$self->name }: $sword_symbol $sound_effect";
});

$drew->swing( 'slash!!' );   # => Drew: ********* slash!!

Everything nicely works the same as the Ruby & Javascript blog examples.

To round things off, below is the complete example but with MooseX::Declare sugar stirred into the pot.

use Modern::Perl;
use MooseX::Declare;

class Ninja with MooseX::SingletonMethod::Role is mutable {
    has name => ( is => 'rw', isa => 'Str' );
}

my $drew = Ninja->new( name => 'Drew' );
my $adam = Ninja->new( name => 'Adam' );

###########################################################

class Ninja is mutable {    
    method battle_cry {
        say $self->name . ' says zing!!!'; 
    }
}

$drew->battle_cry;   # => Drew says zing!!!
$adam->battle_cry;   # => Adam says zing!!!

###########################################################

$drew->add_singleton_method( throw_star => sub {
    say "throwing star";
});

$drew->throw_star;   # => throwing a star

###########################################################

$drew->${ \'battle_cry' };   # => Drew says zing!!!

###########################################################

my $colour_name = 'black';

Ninja->meta->add_method( colour => sub {
    my $self = shift;
    say "${ \$self->name }'s colour is $colour_name";
});

$drew->colour;    # => Drew's colour is black
$adam->colour;    # => Adam's colour is black

###########################################################

my $sword_symbol = '********';

$drew->add_singleton_method( swing => sub {
    my ($self, $sound_effect) = @_;
    say "${ \$self->name }: $sword_symbol $sound_effect";
});

$drew->swing( 'slash!!' );   # => Drew: ********* slash!!

/I3az/

PS. If you want Moose in Javascript then have a look at Joose

Advertisement

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 )

Connecting to %s

%d bloggers like this: