dynamically attaching a method to a class in perl6

lilstevey on 2009-11-30T22:21:22

In case you've just tuned in, I'm trying to learn a bit of perl6 by attempting to create a simple RMI system. And with that, once more into the breach...

Since my last petty fiddling there has been another release of rakudo, so I feel like I should begin with a swift re-installation of rakudo - using the "git clone gen-parrot technique"

Whilst thats running I'll make a few notes. After I looked at the server side of things, I began to have a look at the client. In perl5 I'd tend to use AUTOLOAD to fullfill a variety of object calls on a method, so I thought it worth a punt to have a play in that direction. I didn't get very far, but wasn't that motivated as given the processing needed to generate a method proxy, and also the perl6 Type-checked idium, it seems to me to be more of a composition rather than on call issue?

Whilst I've been doing other things, perl6 has marched forward. I was particulary interested in a use post from Jonathan Worthington, which pointed to a lovely doc on The Rakudo Metamodel.

Of particular interest was this item in the "Package meta-object API (aka HOW API)" section:

add_method($meta, $name, &code_ref)
Adds a method to the methods table of $meta under the given $name and with the given implementation.

Could I use this to generate a proxying class to fullfill a role? If so, the prospect is quite exciting.

Lets have a play-then-think go with it, starting off with TestRole as used in my Nov. 11 use.perl post.

And then I think... Maybe I'm getting ahead of myself. Maybe I should start off where the Nov 11th post left off.

From this post, I'll modify it a little using perl6's very funky iteration syntax, and start off with:

thursday.pl use v6;

use TestRole;

my $r = TestRole;

my $c = class{};

my $code = { say "bloot bloot I am not a newt" };

for $r.^methods(:local) -> $m
{
   my $mn = $m.name;
   say "$mn";
   # Do something to add $code to class $c with method $mn
}

Sometime, between multiple distractions, and blogging $this, the compilation and make has finished. It's now all done, and I'm left contemplating the contents of the "# Do something..."

Much playing follows. Needless to say - its not as simple as add_method($c, $mn, $code), though the output is mildly curious:

C:\ ... >perl6 thursday.pl
randomWWWRRRChars
Could not find non-existent sub add_method in Main (file src\gen_setting.pm, line 295)

Which seems odd, because it's not the first method in the Role. note - In case anyone is interested, thats a metaphorical thursday, from police squad... ( 6:00 minutes if anyone is interested ). All these years I thought it was tuesday...

I wasn't expecting that to work, but aren't sure as to how I get this command working. The temptation is to try #perl6, which is perhaps the friendliest IRC channel I've ever seen, and it's the common sense place to be, but much to my shame, I didn't spend enough time on IRC in the mid 90's - instead I was writting HTML templating systems in perl and playing with POV. That and down the pub. Well, mostly down the pub. Since then, having not gained experience, I've found IRC to be an intimidating place. Even though #perl6 appears to be one of the most welcoming places on earth, there still seems to be a bit of crypticalness to some of the syntax shown when I've been lurking. Some of the behavour suggests bots and I'm not too sure if "thanks" carries the same weight as a ++ postfix. Added to that, the people on their are doing great things, and I'm not sure I want to distract them with my petty problems, given that my free time is rapidly evapourating...

OK, I'm being pathetic. Very very pathetic. Better see if anyone is online, and can help. Off to #perl6 after checking the #perl6 logs in order to retrolurk.

Once again #perl6 were very very nice. I should declare that I googled up IRC etiquette before venturing forth ( though it's not the most useful document on the internet ). masak and diakopter were very helpfull (and friendly), Apparently the code that will provide the one liner I require is apparently being worked upon by jnthn++, but, for now, eval may give the solution I need.

for now, however, bed calleth... goodnight world...

And wakey-wakey post worky. Top Gear is on. BBC iplayer is great. May has been flying a caravan and Clarkson and Hammond are covering the Lancia.

Earlier today, on the borderline of yesterday, masak provided the following example during our IRC conversation, whilst taking part in other discussions. I'm slightly in awe of the multitasking:

class A { if rand < .5 { eval("method foo() \{ say q[foo] }") } else { eval("method bar() \{ say q[bar] }") } }; A.new.?foo; A.new.?bar

After a little hammering at the keyboard I come up with the following:

friday.pl use v6;

use TestRole;

my $r = TestRole;

my &code = { say "bloot bloot I am not a newt" };

class proxy
{
   for $r.^methods(:local) -> $m
   {
      my $mn = $m.name;
      eval "method $mn () \{ &code() }";
   }
}

my $i = proxy.new();
$i.method1();

Running it does the following:

C:\ ... >perl6 friday.pl
bloot bloot I am not a newt

Woot! Enthused, I fire up the the server from my November 24 use perl journal, copy the RmiClient class from my November 09, 2009 post, and type furiously:

saturday.pl use v6;

use TestRole;
use RmiClient;

my $p = RmiClient.new(url => "http://localhost:8888/");

my $r = TestRole;

my &code = { $p.proxy( $_ ) };

class proxy
{
   for $r.^methods(:local) -> $m
   {
      my $mn = $m.name;
      eval "method $mn () \{ return &code( \"$mn\" ) }";
   }
}

my $i = proxy.new();
say $i.method1();

And, joy of joys:

C:\ .. >perl6 saturday.pl
1 - method one

It needs a heavy dose of refactoring, but its a start, and being a start, a suitable end to this post... I might start the next one by ensuring my environmental variables are pointing to the rakudo I started building at the start of this post.