Home > Perl6 > Callbacks and Perl 6

Callbacks and Perl 6

use v6; #source http://gist.github.com/544153

It’s quite tempting to make assumptions about Perl 6 because it resembles constructs from other languages. Most of those assumptions are wrong and as a result spawn anger and mischief.

There are mind traps one might step in. One of those traps are the assumption that a class and the resulting object are the same thing. That might be true for simple low level languages like c++ and Java (kekeke :), for Perl 6 it isn’t. That’s not much of a problem until you try to do something that’s supposed to be quite simple in a dynamic language.

A Callback

class A {
  our method m1(){} # our is needed to see ::m1 outside of the class
}

my $o = A.new();
say (&A::m1).WHAT;
#>Method()

Perl6 is a dynamic language and there is no reason why there shouldn’t be another object system (or better a way to create P6 Objects) that does not use classes. We need to ask the object or it’s meta object for a reference to a method (kind of, I will explain later).

#say $o.^can('m1').WHAT;
#rakudo does not support .WHAT in P6Invocation, if it would it would say
#>P6Invocation()

#say 'yes' if &A::m1 ~~ $o.can('m1');
#rakudo does not support .ACCEPTS in P6Invocation

Nontheless it wont be the same anyways because .can will return an iterator over all methods that match that name. On top of that there are multi methods and a few other tarpits.

But what would work?

class Sender {
  has @.callbacks; # takes 3 items at a time: Any $obj, Str $name, Code $func

  multi method add_callback($o, Str $name){
    @.callbacks.push($o, $name, $o.can($name));

    return self;
  }

  method run_callbacks(){
  # This fellow will make a difference of (object, method) paires and simple
  # functions. We call them with different parameters to make sure we can tell
  # the difference and to show off MMD.
    for @.callbacks -> $o, $name, $f {
      if $o {
	$o.$f("foo");
      } else {
	$f(4, 2);
      }
    }

    return self;
  }

  multi method add_callback(Code $f){
    @.callbacks.push(Any, Any, $f);
  }
}

Now the mean part. We have an object that wants to be called back and got two functions that might be up for the task, depending on their parameters.

class Rcpt {
  has $.name = die 'I need a name.';
  multi method callback1($p1){
    say "callback1 of $.name has to say: $p1";
  }

  multi method callback1(Int $i, Int $j){
    say '$i * $j = ' ~ $i * $j;
  }
}

my $sender = Sender.new;
my $rcpt1 = Rcpt.new(:name('rcpt1'));

$sender.add_callback($rcpt1, 'callback1');

Another trap comes from somebody coming along and starting to poke around in Rcpt. Extending classes is NYI in Rakudo, so we are not really doing it right here.

use MONKEY_TYPING;

#supersede class Rcpt {
#  method callback1($p1){
#    say "callback1 of $.name would have to say: $p1";
#  }
#}
#
#$sender.run_callbacks();

The question is, what function would be called as a method of $rcpt1. The old one or the new one. Should we call .^can before we call the function? It might even be a case of “Just don’t do it.”.

#use AllYourClassesAreBelongToMe;

Did something happen to Rcpt while loading that package? Maybe.

We can get around .^can alltogether by forming a closure, what most dynamic savy folk would have done anyways. Making sure the right arguments land in the right spot.

$sender.add_callback(-> *@args {$rcpt1.callback1(|@args)});
# There are now two callbacks registered. One as a object/function pair and
# another as a simple function with no bound object. The binding happends
# in a closure that passes it's arguments on as they come in.

$sender.run_callbacks();
#>callback1 of rcpt1 has to say: foo
#>$i * $j = 8

#adding a multi NYI in Rakudo
#augment class Rcpt {
#  multi method callback1(Str $s1, Str $s2){
#  	 what_ever($s1, $s2);
#  }
#}

Even after fooling around with Rcpt and adding another candidate for callback1, Rakudo would call the right method if supplied with two strings. Late binding and signatures working hand in hand to do what we mean. Perl 6 is very perlish if you ask me. :)

Advertisements
Categories: Perl6
  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Please log in using one of these methods to post your comment:

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

%d bloggers like this: