Perl6 metaprogramming update
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/