Perl 6: Exciting Method Invocation

Perl 6 provides many new and interesting approaches to method invocation.  New constructs in the language allow the developer to define how many matching methods are called, how they are called, as well as a few other things.

In Line Mutators

Perl 6 supports the idea of inline mutators.  In Perl 5 it isn't too uncommon to see code like this:

@array = sort @array

It is common enough in the Perl community to see "assign this mutated value back into the variable it came from" that Perl 6 gives a cleaner way.  The same code in Perl 6 could be written:

@array .= sort

The line above says to take @array, sort it, and put the values back in @array all in one fluid motion.  Of course, there is one motion that developers go through that is so common most probably don't think about it:

my SVG $svg_serializer = SVG.new;

Thankfully, .= can use used here to assign a value into $svg_serializer more cleanly:

my SVG $svg_serializer .= new;

Invoking Multiple Matched Methods

In Perl5 (and other languages) one often finds code litered with statements like this:

$foo->frobinicate() if $foo->can('frobinicate');

That gets old after a while.  Perl 6 solves this, and a few other problems, with a new approach to method calls that allows the developer to request 0 or 1, 1, 1 or more, or any number of methods be called at a time.  So, for example, the Perl6 equivalent of above is:

$foo.?frobinicate;

The above code will invoke the frobinicate method on $foo if one exists.  However, if no method exists that matches that criteria then nothing will be executed and instead of dying the statement simply returns Nil.

As I mentioned there are other options here also, for example if the developer wanted to execute all of the 'frobinicate's that existed within the inheritance hierarchy of $foo they could do either:

$foo.*frobinicate;

$foo.+frobinicate;

As readers can probably guess '.*' will invoke 0 or more methods named 'frobinicate' on $foo returning Nill if none exist.  That leaves '.+' to invoke 1 or more matching methods, the line dies if it finds no matching methods.

Here is an example of the above:

class Dog {

   method talk { 'bark' }

}

class TalkingDog is Dog {

   method talk { 'Hello' }

}

my TalkingDog $td .= new;

$td.talk # returns 'Hello'

$td.?talk # returns 'Hello'

$td.*talk # returns ('Hello', 'bark')

$td.+talk # also returns ('Hello', 'bark')

$td.*calculate_pi # returns Nil

$td.+calculate_pi # dies

$td.?calculate_pi # returns Nil

$td.calculate_pi # dies

Parallel Invokation

Perl 6 has an incredibly exciting new operator called the hyperoperator.  The hyperoperator indicates that the methods being invoked can be dispatched in parallel.  This makes simple cases of parallel execution very simple to do.  To do this, simply prepend '>>' between the object and the invocation operator.  For example:

@foo>>.frobinicate

This would invoke 'frobinicate' on all the elements in @foo in parallel.  

The hyperoperator can be combined with the previous topic of invoking all the methods that match.  This makes it very simple to invoke all of the possible methods on an object in parallel:

$foo>>.*frobinicate()

Here is a simple, but more fleshed out example to wrap things up:

class Department {

   has @.employees;

   has $.name;

   method gen_print_info { return "$.name:\n" ~"\t\t" ~ @.employees.sort.join(', ')}

}

my @company = (

   Department.new( name => 'Accounting', 'employees' => <Jeff Jane Susan>),

   Department.new( name => 'Security', employees => <Alice Bob>),

   Department.new( name => 'Marketing', employees => <Margaret Terry Lawrence>),

   Department.new( name => 'Development', employees => <Matt Fred Steve Joe Alith Jie>)

)

my @print_info = @company>>.gen_print_info;

The example above would execute gen_print_info on all of the Department typed objects in @company.

 

Further Reading

Perl 6: Coding with Class

This entry will focus on creating and using classes in Perl 6.  Perl 6's class system greatly expands on the approach of Perl 5 in many ways, a few of which are giving a standard new method and providing an approach for easily declaring attributes on a class.

Here is a very simple example of a Perl 6 class:

This example shows a few basic concepts.  First there is the new class keyword.  Named classes can easily be declared in one of two ways.  The example above, with curly braces, is useful when defining more than one class in a file or providing for some code to execute outside of the scope of the class when loading.  Without the curly braces is also legal, however it means that the rest of the file is the class definition.

Additionally, this shows our first attribute, name.  The name attribute is defined as being of type Str.  The twigil '.' in this case indicates that this attribute should have a public accessor.  In this case that accessor is read-only because we did not define it otherwise (see below).

The eat and sleep method were also defined.  The sleep method uses the name attribute on the class in the string that it says.  It can do this without using $self because $. implies the object the method was invoked on.  So, the eat method could have also been rewritten like it is for the sleep method.

Instantiating new objects of type Animal and using their methods is simple:

A more complicated example is below.  In this one two more classes, 'Dog' and 'Tail', have been defined:

The Dog class has a couple new interesting additions.  The first thing to notice is that Dog inherits from Animal via the is keyword on the first line.  The tag attribute is defined as 'rw'.  This means that public accessors for both acquiring and mutating the value of the tag are provided.  The tail attribute has a '!' as a twigil.  This twigil indicates that no public accessors should be defined.  However, an instance of the Dog class delegates to the tail attribute when the wag method is invoked upon it.  This means that when someone calls $a_dog.wag they are really calling wag on $a_dog's $!tail.  Delegation is a very handy way to improve code reuse, Perl 5 developers who use Møøse should be familiar with it.  Finally the tail also has a default value of a new Tail object.

This new class can be easily used like the following example:

However, what if we didn't want to use the simple Tail class for our dog's tail.  We could pass in an object of another class that had a wag method on it like so:

That pretty much wraps up this entry on Perl 6's class system.  The system includes many more powerful features that should be covered at a later date.

Further Reading:

Basic Moose Week 1: Creating a Class

*** Update:  Thanks to Kent Fredric (@kentnl) for catching my mistake on his MooseX::Has::Sugar***

Perl5's object system is impressive in its simplicity.  From that simplicity it gains an incredible flexibility which both matches Perl and allows for amazing things.  However, it is easy to find patterns created from the spartan nature of the system.  This last point has caused many people to design new object interfaces on top of Perl's object system.  The most robust and popular of these is Moose.  This first tutorial will show you a simple way to create classes using Moose.

Moose allows the user to easily declare the attributes that are provided on a class along with metadata about those attributes.  This metadata defines many important aspects of the attribute, such as what type of attribute it is, what the permissions are on the attribute, the default value of the attribute, and many other things.  Here is an example of a simple class called employee:

This class definition does several things, so let's break it down.  First we use Moose, this exports some spiffy 'keywords' like has.  Additionally, it very sneakily uses the strict and warnings pragma in our package which is very convenient.  Next we use the has keyword to define an attribute called pay.  We define this attribute as being both readable and writable through its accessor and we say that the accessor should only accept numbers.  Next, we create another attribute called manager, which has an accessor that both allows reading and writing and only accepts Employee objects.  How does it know that Employees are objects?  Well, Moose has a list of things that it considers types.  If the type is already defined then it uses that type, otherwise it assumes it is a class.

That seems like that could be dangerous though.  For example, what if you typo'd 'Num' to be 'num' or 'NUm' or if you spelled out 'number'?  In these cases Moose would assume that 'num', 'NUm', or 'number' were names of classes and only accept values that were of that class.  Don't worry though, someone has already seen and solved that problem, the solution we will use for this is a combination of MooseX::Has::Sugar and MooseX::Types.  MooseX::Has::Sugar provides us with several predefined 'keywords' that we can use and if we typo we'll get compile time errors.  Additionally, it defines rw and ro (the value for is that indicates readonly) in such a way that we no longer have to provide the 'is =>' portion.  MooseX::Types allows us to predeclare types and organize them into libraries.  Now our class definition looks like this:

This looks much better.  By the way, there are many options to MooseX::Has::Sugar and MooseX::Types so you would really benefit from reading that over.

Let's try and use this class in a script:

Now, if we look at that script we see some very interesting things.  We never explicitly created a new, manager, or salary method but they are all there.  This is because Moose created each of these for us to use.  In fact, it is imperative that when you are using Moose you do not create your own new method, that is very dangerous.

Of course, Moose provides many other meta attributes to define the attributes of your class, some of which are:

  • required - whether calls to new() must include this attribute, can be 1 or 0
  • default - the default value of this attribute or a reference to a sub that will return the default value, it is better to use builder though (see below)
  • lazy - whether this attribute will be built when the object is built or whether Moose will wait until it is first used
  • …and more we'll cover in following weeks

We'll rewrite our class by adding some attributes and adding these meta attributes to all the attributes, but this time we won't use MooseX::Has::Sugar or MooseX::Types:

Builder vs. Default

I mentioned above that you can set the default value of an attribute with default however it is better to use builder.  The builder option takes the name of a subroutine that will return a value for the attribute instead of a subref or actual value.  The benefit of this is that if you inherit from a base class that uses a builder you can easily override the default value by overriding the sub that builds the value, with default it is not so simple.

Caveat

There is one important caveat to mention.  Neither Moose nor any of its extensions are magical and, in fact, none of them actually create new keywords.  Instead, all of these modules are importing methods into your package just like any other tool.  This means that they happen in the same order as you would expect function calls to happen.  It also means you can write them any way you want, however this is a place where following the standard benefits everyone.

Dirty Little Secret

As much as I like the idea of MooseX::Has::Sugar and MooseX::Types I should probably mention that I actually rarely use them.  However, they seem like a good tool to start off with.

Further Reading