loading...

Perl6 Multi Method Signatures : Self Introspection

scimon profile image Simon Proctor Updated on ・3 min read

Perl6 Multi Method Signatures : Self Introspection

I am a big fan of Perl6. One of it's more powerful features are multi subs (and methods) that allow you to handle calls in different ways based on the signature of the call.

Whilst a number of languages have the ability to do multi dispatch Perl6 not only can perform dispatch on the number of arguments or their types it can also choose which code path to follow based on the arguments values. For instance there's the classic Factorial as a recursive multi sub.

multi sub fac(0) { 1 }
multi sub fac(UInt $f where $f > 0) { $f * fac($f-1) }

Here we define two code paths. One where you call the sub with 0 and another where you call it with an unsigned integer greater than 0. That's great but what if you have an object and want to process method calls differently based on the objects field values?

For example you have the following method:

method retrieve-archived-data() {   
    # This won't work if our object has not be archived yet.
    # Fail this call
    fail "Can't Retrieve Data for an object that's never been archived" 
        unless $.archived;

    # Code here that gets archived data from some source. 
    # It takes a while and the above check was added because it used to take a 
    # while and then fail.
}

So at some point this method would take a lot of time looking for the archived data and then fail if it had never been archived. So our intrepid developer put a check in at the top the script to avoid that. The problem with that sort of thing is it soon mounts up. It'd be nice to be able to make it a multi method but how? The $ variable isn't in the signature.

Simple. We add it!

Normally when you call an object method the object you call it on is avaliable in the method as self or $. But you can also give it a different name to use with the method as well for example:

method set-name( $pet : $name ) {
    $pet!name = $name
}

Note that we separate the object name and the rest of the arguments with a : instead of a , as normal. Like other arguments we can add a where clause between the name and the seperator. With this knowledge we can rewrite our method:

multi method retrieve-archived-data( $ where ! $.archived: ) {
    # This won't work if our object has not be archived yet.
    # Fail this call
    fail "Can't Retrieve Data for an object that's never been archived";
}

multi method retrieve-archived-data() {
    # Code here that gets archived data from some source. 
}

Note the trailing : if you miss that out it isn't going to work.

In this way we can remove a lot of the special cases that often pepper method that have been around for a while. Keeping our code lean and easy to read.

I hope you found that interesting. I'm hoping to write some more posts here about Perl6 and why I think that it's well worth some of your time.

Note

I've updated the second example to remove the redundant second check. I should also mention that $ is the anonymous scalar variable (when it's used in the signature). When you are in a method $.foo is another way of saying self.foo.

You can, if you want, name a variable to reference inself of self eg:

method named-access( $name: ) {
    $name.field;
}

In this method $name.field, self.field and $.field will all reference the same object.

Sorry for any confusion.

Posted on by:

scimon profile

Simon Proctor

@scimon

Was an Englishman in Scotland but now back in England. Gamer, coder and voracious devourer of information. Occasionally writes stuff.

Discussion

markdown guide
 

Sorry, Simon, I don't seem to be able to parse this:

Simple. We add it! You can define a name for your object to be used in a method but putting it at the start of the signature followed by :

Do you mean that you are creating $.archived and that the fact that is followed by : defines it?

 

I shall expand on that bit to explain it better.

 

Sorry again, Simon. The trailing colon separates (please check out the typo) the declaration from what?

I may have to work on the wording some more.

But you're separating the object from the other method arguments.