DEV Community

Simon Proctor
Simon Proctor

Posted on • Updated on

Perl6 Multi Method Signatures : Self Introspection

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) }

Enter fullscreen mode Exit fullscreen mode

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.
}

Enter fullscreen mode Exit fullscreen mode

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
}

Enter fullscreen mode Exit fullscreen mode

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. 
}

Enter fullscreen mode Exit fullscreen mode

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;
}

Enter fullscreen mode Exit fullscreen mode

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

Sorry for any confusion.

Top comments (7)

Collapse
 
jj profile image
Juan Julián Merelo Guervós

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?

Collapse
 
scimon profile image
Simon Proctor

I shall expand on that bit to explain it better.

Collapse
 
scimon profile image
Simon Proctor

Ok. I think that's got it.

Thread Thread
 
jj profile image
Juan Julián Merelo Guervós

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

Thread Thread
 
scimon profile image
Simon Proctor

I may have to work on the wording some more.

Thread Thread
 
scimon profile image
Simon Proctor

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

Collapse
 
jj profile image
Juan Julián Merelo Guervós

Thanks!