Skip to content

Perl6 metaprogramming update

October 31, 2010

This post is an update to my Anyone for Perl 6 metaprogramming? article and gist using Rakudo Star (October 2010 release).

Now I expected one change to the code and one optional improvement that I could now make. However along with these I got two extra enforced changes.

Re-opening a class

First the expected change to re-opening a class:

class Ninja is also { ... }

# is now...

augment class Ninja { ... }

However for this to work I needed to add the following:

use MONKEY_TYPING;

A pragmatic addition. If you’re gonna shoot yourself in the foot then at least you have to prepare for it in advance 🙂

NB. Rakudo nicely gave me a fatal warning when I tried to re-open the class and politely told me that use MONKEY_TYPING was needed it I wanted to augment class Ninja.

Applying a role to an object (instance)

Now the next change was optional but it was a more succinct way to add a role to an object. Previously I had to create a role and then apply it to object:

role ThrowStar {
  method throw_star { say "throwing star" }
}

$drew does ThrowStar;

Now with Rakudo Star I can apply an anonymous role directly:

$drew does role {
  method throw_star { say "throwing star" }
};

Something I didn’t expect

The final change to the code was something unexpected. I got the following error:

===SORRY!===
Quoted method name requires parenthesized arguments at line 50, near "; # =>"

This was tied to this line of code:

$drew.'battle_cry';     # => Drew says zing!!!

I am not sure if this is a change to Perl6 spec but it now requires extra parenthesis:

$drew.'battle_cry'();     # => Drew says zing!!!

… and finally

My original post from beginning of the year was me just kicking the Rakudo tyres. I’m now looking forward to taking it out for a proper test drive around the block 🙂

Below is the complete revised code:

use v6;
use MONKEY_TYPING;

class Ninja {
    has Str $.name is rw;
}

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


###########################################################
# Reopen Ninja class ("is also" does the biz) 
# and add 'battle_cry' method

augment class Ninja {
    method battle_cry {
        say $.name ~ ' says zing!!!'; 
    }
}

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


###########################################################
# add 'throw_star' method to $drew object by 
# applying ("does") role to it (Singleton method)

$drew does role {
    method throw_star { say "throwing star" }
};

$drew.throw_star;     # => throwing a star


###########################################################
# call method dynamically

$drew.'battle_cry'();     # => Drew says zing!!!


###########################################################
# add "colour" method closing over $colour_name (ie. closure):

my $colour_name = 'black';

augment class Ninja {
    method colour { say "{$.name}'s colour is $colour_name" }
}

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

# "defining a method dynamically on an instance that closes 
# over local scope and accesses the instance’s state"
#
# Opps - Class method slipped in while working it out.
# $drew.^add_method() does a singleton method.. nice!

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

$drew.^add_method( 'swing', method ( Str $sound_effect ) { 
    say "$.name: $sword_symbol $sound_effect";
} );

$drew.swing( 'slash!!' );

Happy halloween!

/I3az/

No comments yet

Leave a comment