Day 11: Classes, attributes, methods and more

Day 11: Classes, attributes, methods and more

We excitedly tear the shiny wrapping paper off today’s gift, and inside we find something that nobody could object to! It’s the Perl 6 object model, in all its class-declaring, role-composing, meta-modelling glory. But before we get too carried away with the high-powered stuff, let’s see just how easy it is to write a class in Perl 6.

class Dog {
    has $.name;
    method bark($times) {
        say "w00f! " x $times;

We start off by using the class keyword. If you’re coming from a Perl 5 background, you can think of class as being a bit like a variant of package that gives you a bunch of classy semantics out of the box.

Next, we use the has keyword to declare an attribute along with an accessor method. The . that you see in the name is a twigil. Twigils tell you something special about the scoping of a variable. The . twigil means “attribute + accessor”. Other options are:

has $!name;       # Private; only visible in the class
has $.name is rw; # Generates an l-value accessor

Next comes a method, introduced using the method keyword. method is like sub, but adds an entry to the methods table of the class. It also automatically takes the invocant for you, so you don’t have to write it in the parameter list. It is available through self.

All classes inherit a default constructor, named new, which maps named parameters to attributes. We can call this on Dog – the type object of the Dog class – to get a new instance.

my $fido = => 'Fido');
say $;  # Fido
$fido.bark(3);   # w00f! w00f! w00f!

Notice that the method call operator in Perl 6 is . rather than Perl 5’s ->. It’s 50% shorter, and will be familiar to developers coming from a range of other languages.

Of course, there’s inheritance, so we can introduce a yappy puppy.

class Puppy is Dog {
    method bark($times) {
        say "yap! " x $times;

There’s also support for delegation.

class DogWalker {
    has $.name;
    has Dog $.dog handles (dog_name => 'name');
my $bob = => 'Bob', dog => $fido);
say $;      # Bob
say $bob.dog_name;  # Fido

Here, we declare that we’d like calls to the method dog_name on the class DogWalker to forward to the name method of the contained Dog. Renaming is just one option that is available; the delegation syntax offers many other alternatives.

The beauty is more than skin deep, however. Beneath all of the neat syntax is a meta-model. Classes, attributes and methods are all first class in Perl 6, and are represented by meta-objects. We can use these to introspect objects at runtime.

for Dog.^methods(:local) -> $meth {
    say "Dog has a method " ~ $;

The .^ operator is a variant on the . operator, but instead makes a call on the metaclass – the object that represents the class. Here, we ask it to give us a list of the methods defined within that class (we use :local to exclude those inherited from parent classes). This doesn’t just give us a list of names, but instead a list of Method objects. We could actually invoke the method using this object, but in this case we’ve just ask for its name.

Those of you into meta-programming and looking forward to extending the Perl 6 object model will be happy to know that there’s also a declarational aspect to all of this, so uses of the method keyword actually compile down to calls to add_method on the meta-class. Perl 6 not only offers you a powerful object model out of the box, but also provides opportunities for it to grow to meet other future needs that we didn’t think of yet.

These are just a handful of the great things that the Perl 6 object model has to offer; maybe we’ll discover more of them in some of the other gifts under the tree. :-)

Day 10: A Regex Story

Day 10: A Regex Story

On this tenth day of advent, we have the gift of a story …

Once upon a time in a land closer than you might think, an apprentice Perl 6 programmer named Tim was working on a simple parsing problem. His boss (let’s just call him Mr. C) had asked him to parse log files containing inventory information to make sure that there were only valid lines within the file. Each valid line within the file looked like this:

    <part number> <quantity> <color> <description>

So the Perl 6 apprentice, having some familiarity with regular expressions wrote a nice little regex that could be used to identify valid lines. The code that validated each line looked like this:

    next unless $line ~~ / ^^ \d+ \s+ \d+ \s+ \S+ \s+ \N* $$ /

The ~~ operator causes the regex on the right hand side to be matched against the scalar on the left hand side. In the regex itself, ^^ matches the beginning of a line, \d+ matches one or more digits (as the part number and quantity were so composed), \S+ matches one or more non- whitespace characters, \N* matches zero or more non-newline characters, \s+ matches whitespace in between each of these and $$ matches the end of a line. This being Perl 6, these individual components of the regex could be spread out a bit with spaces in between so that it could be more readable. All was good.

But then Mr. C decided that it would be nicer if the individual pieces of information could also be extracted from each in addition to validating it. Tim thought, “No problem, I’ll just use capturing parentheses”. And that’s just what he did:

    next unless $line ~~ / ^^ (\d+) \s+ (\d+) \s+ (\S+) \s+ (\N*) $$ /

After a successful pattern match, each parenthesized portion is available either as part of the match object itself ($/) via $/[0], $/[1], $/[2], or $/[3]. Or it could be accessed via the special variables $0, $1, $2, or $3. Tim was happy. Mr. C was happy.

But then it was discovered that some of the lines didn’t separate the color from the description and that these lines should be considered valid too. Lines where the color was integrated into the description were written a special way. They were always of the form:

    <part number> <quantity> <description> (<color>)

Where description, as before, could be any number of characters including spaces. “Blah!” thought Tim, “now this simple parser suddenly seems more complicated.” Luckily, Tim knew of a place to ask for help. He quickly logged on to, joined the #perl6 channel, and asked for help. Someone suggested that he should name the individual parts of his regex to make things easier and then use an alternation to match one or the other alternatives for the last part of the regex.

First, Tim tried naming the parts of his regex. Looking at the synopsis for Perl 6 regex, Tim found he could assign into the match object, so that’s what he did:

    next unless $line ~~ / ^^ $<product>=(\d+) \s+ $<quantity>=(\d+) \s+ $<color>=(\S+) \s+ $<description>=(\N*) $$ /

Now, after a successful match, the individual pieces are available via the match object or via special variables $<product>, $<quantity>, $<color>, and $<description>. This was turning out easier than expected and Tim was feeling quite confident. Next he added the alternation to distinguish between the two different valid lines:

    next unless $line ~~ / ^^
        $<product>=(\d+) \s+ $<quantity>=(\d+) \s+
        | $<description>=(\N*) \s+ '(' $<color>=(\S+) ')'
        | $<color>=(\S+) \s+ $<description>=(\N*)

In order to isolate the alternation from the rest of the regex, Tim surrounded it with grouping brackets ([ and ]). These group a portion of a regex much like parentheses only without capturing into $0 and friends. Since he needed to match literal parentheses, Tim took advantage of another useful Perl 6 regex feature: quoted strings are matched literally. And because of the assignments within the regex, $<color> and $<description> always contain the appropriate part of the string.

Tim was elated! He showed his code to Mr. C and Mr. C was elated too! “Well done Tim!” said Mr. C.

Everybody was happy. Tim beamed with pride.

However, after the initial glow of success faded, Tim started looking at his work with a more critical eye. For some of the lines where the color was at the end of the description, it was described as “( color)” or “( color )” or “( color )”. His current regex worked, but it would include the color as part of the description and wouldn’t set $<color> at all. That hardly seemed appropriate. Tim initially fixed this by adding more \s*:

    next unless $line ~~ / ^^
        $<product>=(\d+) \s+ $<quantity>=(\d+) \s+
        | $<description>=(\N*) \s+ '(' \s* $<color>=(\S+) \s* ')'
        | $<color>=(\S+) \s+ $<description>=(\N*)

This worked well, but the regex was starting to look a little cluttered. Again, Tim turned to #perl6 for help.

This time someone named PerlJam piped up, “Why don’t you put your regex in a grammar? That’s what you’re effectively doing by assigning each piece to a variable within the match object.” Wha??? Tim had no idea what PerlJam was talking about. After a brief exchange, Tim thought he understood and knew where to look if he needed more information. After thanking PerlJam, he went back to coding. This time the regex virtually disappeared as it turned into a grammar. Here’s what that grammar and matching code looked like:

grammar Inventory {
    regex product { \d+ }
    regex quantity { \d+ }
    regex color { \S+ }
    regex description { \N* }
    regex TOP { ^^ <product> \s+ <quantity>  \s+
                | <description> \s+ '(' \s* <color> \s*  ')'
                | <color> \s+ <description>

# ... and then later where the match happens
next unless Inventory.parse($line);

“Well,” thought Tim, “it is certainly more organized.”

Each of his variables in the previous incarnation of the regex simply became named regex within the grammar. Within Perl 6 regex, named regex are matched by simply enclosing the name within angle brackets (< and >). The specially named regex TOP is used when Grammar.parse is called with the scalar to match against. And the behavior is exactly the same as before because when a named regex matches as part of another regex, the text that was matched is saved in the match object and referenced by that name.

And though there was still room for improvement, both Tim and Mr. C were very happy with the result.

The End

* At the time of posting, Rakudo cannot correctly use this grammar to parse lines in the format

    <part number> <quantity> <description> (<color>)
Day 9: Having beautiful arguments (and parameters)

Day 9: Having beautiful arguments (and parameters)

On the ninth day of advent, we unwrap… the syntax for parameters and arguments.

You may or may not be familiar with the way Perl 5 does parameter handling in subroutines. It goes something like this:

  sub sum {
    [+] @_
  say sum 100, 20, 3;  # 123

The [+] is Perl 6, but we might as well have written that as my $i = 0; $i += $_ for @_; $i, and the above would have worked in Perl 5. The important point is that, in Perl 6 as well as in Perl 5, when you call a subroutine, your parameters can be found in @_. You unpack them, and you do your thing.

This system is extremely flexible, because it doesn’t impose any mechanism on the handling of parameters; it’s all up to you, the programmer. It’s also tedious, and favours boilerplate to some extent. Take this fictional example:

  sub grade_essay {
    my ($essay, $grade) = @_;
    die 'The first argument must be of type Essay'
      unless $essay ~~ Essay;
    die 'The second argument must be an integer between 0 and 5'
      unless $grade ~~ Int && $grade ~~ 0..5;

    %grades{$essay} = $grade;

(You’d have to use isa instead of ~~ and $grades instead of %grades to make this work in Perl 5, but apart from that, this code would work in Perl 5 as well as in Perl 6.)

Now, for a moment, look at the above, and despair about the amount of manual unpacking and verification you have to make. Feel it? Good.

Perl 5 solves this by giving you excellent CPAN modules, such as Sub::Signatures and MooseX::Declare, for example. Just include them, and you’re set.

Perl 6 solves it by giving you a few more defaults. By “a few more”, I really mean “make sure you don’t drool on your keyboard”. In Perl 6, I would have written the above routine like this:

  sub grade_essay(Essay $essay, Int $grade where 0..5) {
    %grades{$essay} = $grade;

Now we’re talking. It has the same runtime semantics as the longer version above. And I didn’t have to import any CPAN modules, either.

Sometimes it’s convenient to provide default values to parameters:

  sub entreat($message = 'Pretty please, with sugar on top!', $times = 1) {
    say $message for ^$times;

The default values need not be constants, and they can in fact use earlier parameters:

  sub xml_tag ($tag, $endtag = matching_tag($tag) ) {...}

If your default is unspecified, just mark the parameter as optional without giving it a default, by using ?:

  sub deactivate(PowerPlant $plant, Str $comment?) {
    say $comment if $comment;

One feature I particularly like is that you can refer to the parameters by name when calling, passing the named arguments in any order you like. I can never remember the parameter order in functions like this:

  sub draw_line($x1, $y1, $x2, $y2) { ... }

  draw_line($x1, $y1, $x2, $y2);  # phew. got it right this time.
  draw_line($x1, $x2, $y1, $y2);  # dang! :-/

There’s a way to refer to the parameters by name, which makes this problem melt away:

  draw_line(:x1($x1), :y1($y1), :x2($x2), :y2($y2));  # works
  draw_line(:x1($x1), :x2($x2), :y1($y1), :y2($y2));  # also works!

The colon means “here comes a named argument”, and the whole construct is to be read as :name_of_parameter($variable_passed_in). There’s a short form that can be used when the parameter and the variable happen to have the same name, though:

  draw_line(:$x1, :$y1, :$x2, :$y2);  # works
  draw_line(:$x1, :$x2, :$y1, :$y2);  # also works!

I like the short form. I find it causes my code to be more readable.

If you, as the API author, want to force people to use named arguments — which might actually be appropriate in the case of draw_line — you need only supply the colons in the subroutine signature.

  sub draw_line(:$x1,  :$y1,  :$x2,  :$y2 ) { ... }  # optional nameds

But be careful, named arguments are optional by default! In other words, the above is equivalent to this:

  sub draw_line(:$x1?, :$y1?, :$x2?, :$y2?) { ... }  # optional nameds

If you want to explicitly make parameters required, you can append a ! to them:

  sub draw_line(:$x1!, :$y1!, :$x2!, :$y2!) { ... }  # required nameds

Now the caller has to pass them, just as with ordinary positional parameters.

What about varargs? Say you want an arbitrary number of arguments passed in. No problem: just make the parameter an array and precede it with a *:

  sub sum(*@terms) {
    [+] @terms
  say sum 100, 20, 3;  # 123

I use the same example as we started out with to make a point: when you don’t supply a signature to your subroutine, what you end up with is the signature *@_. This is the signature that emulates Perl 5 behaviour.

But an array with a * in front of it (a ‘slurpy array’) only captures positional arguments. If you want to capture named arguments, you’d use a ‘slurpy hash’:

  sub detect_nonfoos(:$foo!, *%nonfoos) {
    say "Besides 'foo', you passed in ", %nonfoos.keys.fmt("'%s'", ', ');

  detect_nonfoos(:foo(1), :bar(2), :baz(3));
       # Besides 'foo', you passed in 'bar', 'baz'

Oh, and this might be a good time to mention that you can also pass in named parameters with a more hash-like syntax, like so:

  detect_nonfoos(foo => 1, bar => 2, baz => 3);
       # Besides 'foo', you passed in 'bar', 'baz'

Here’s one important difference to Perl 5: parameters are readonly by default:

  sub increase_by_one($n) {

  my $value = 5;
  increase_by_one($value);  # boom

There are two chief reasons for making parameters readonly; one being efficiency. Optimizers like when variables are read-only. The other reason has to do with encouraging the right habits in the programmer, and make it slightly more cumbersome to be sloppy. Functional programming is good not only for the optimizer, but for the soul as well.

Here’s what you need to do to make the above work:

  sub increase_by_one($n is rw) {

  my $value = 5;
  say increase_by_one($value);  # 6

Sometimes is rw is what you want, but sometimes you’d rather be modifying a copy of whatever was sent in. That’s when you use is copy:

  sub format_name($first, $middle is copy, $last) {
    $middle .= substr(0, 1);
    "$first $middle. $last"

The original will be left unchanged.

In Perl 6, when you pass in an array or a hash, it doesn’t flatten out over several arguments by default. Instead, you have to use the | to make it flatten.

  sub list_names($x, $y, $z) {
    "$x, $y and $z"

  my @ducklings = <huey dewey louie>;
  try {
  say $!;                       # 'Not enough positional parameters passed;
                                #  got 1 but expected 3'
  say list_names(|@ducklings);  # 'huey, dewey and louie'

Similarly, if you flatten a hash, its contents will be sent in as named arguments to the routine.

Just as you can pass in arrays and hashes, you can also pass in code blocks:

  sub traverse_inorder(TreeNode $n, &action) {
    traverse_inorder($n.left, &action) if $n.left;
    traverse_inorder($n.right, &action) if $n.right;

The three sigils are really type constraints:

  @  Array    (actually, Positional)
  %  Hash     (actually, Associative)
  &  Code     (actually, Callable)

…with the $ sigil working as the unconstrained version.

Watch out! An easy trap that people fall into is specifying the type constraint twice, both through a type and through a sigil:

  sub f(Array @a) { ... }  # WRONG, unless you mean Array of Array
  sub f(      @a) { ... }  # probably what you meant
  sub f(Int   @a) { ... }  # Array of Int

If you followed through to this point, you deserve another Perl 6 one-liner.

  $ perl6 -e '.fmt("%b").trans("01" => " #").say for <734043054508967647390469416144647854399310>.comb(/.**7/)'
  ###           ##   ###
  # #  ##  # ##  #  #
  ### #  # ##    #  ####
  #   #### #     #  #   #
  #   #    #     #  #   #
  #    ##  #     ##  ###
Day 8: .comb your constraints

Day 8: .comb your constraints

We have hit the point where the previous gifts are useful for the current gifts. Today is a dual set: the comb method and the idea of constraints.

Similar to the static types previous defined, constraints allow fine control in writing subroutines and methods. In many other programming languages, you have to pass parameters into a subroutine and then validate the input that comes in. With constraints, you can do the validation right in the declaration.

Take this basic example. If the integer is even, I don’t want to deal with this subroutine. In Perl 5, it would be written something similar to this:

sub very_odd
    my $odd = shift;
    unless ($odd % 2)
        return undef;
    # Process the odd number here.

In Perl 6, this can be simplified thusly:

sub very_odd(Int $odd where {$odd % 2})
    # Process the odd number here

If you attempt to call very_odd with an even number, you will get an error. Do not fret though: you can use the multi sub functionality to give even numbers a chance to shine…maybe. ;)

multi sub very_odd(Int $odd where {$odd % 2})
    # Process the odd number here
multi sub very_odd(Int $odd) { return Bool::False; }

These constraints can be useful when paired with the .comb method. What exactly is .comb? For those that brush their own hair, you generally use a comb to get the strands you want and settle them somewhere on your head. For those that like using .split, it’s the opposite: instead of separating a Str by what you don’t want, you separate it by what you do. This simple piece of code should demonstrate that:

say "Perl 6 Advent".comb(/<alpha>/).join('|');
say "Perl 6 Advent".comb(/<alpha>+/).join('|');

Regex patterns will most likely be covered another day, but a quick preview won’t hurt. The first line will print P|e|r|l|A|d|v|e|n|t: it gets every alphabetic character and puts it into a temporary array. It is then joined together with the pipe character. The second line is similar, only it grabs as many alphabetic characters as it can, resulting in Perl|Advent.

The power of .comb is much more, however. Once you have combed out what you wanted, you can manipulate the strands. If you have a basic string of ASCII hex characters, you can use the hyperoperators to change each piece into the ASCII equivalent!

say "5065726C36".comb(/<xdigit>**2/)».fmt("0x%s")».chr
# Outputs "Perl6"

For those intimidated by that, you can find also use the .map method.

say "5065726C36".comb(/<xdigit>**2/).map: { chr '0x' ~ $_ } ;
# Outputs "Perl6"

Remember, this is Perl. There is more than one way to do it. ☺

With all of the gifts that have been presented today, I now have a challenge for all of you. With the assistance of Kyle Hasselbacher, I was able to make a decent version of the ancient Caesar Cipher using constraints, .comb, and the old style .map.

use v6;

sub rotate_one( Str $c where { $c.chars == 1 }, Int $n ) {
    return $c if $c !~~ /<alpha>/;
    my $out = $c.ord + $n;
    $out -= 26 if $out > ($c eq $c.uc ?? 'Z'.ord !! 'z'.ord);
    return $out.chr;

sub rotate(Str $s where {$s.chars}, Int $n = 3)
    return ($ { rotate_one( $_, $n % 26 ) }).join( '' );

die "Usage:\n$*PROGRAM_NAME string number_for_rotations" unless @*ARGS == 2;

my Str $mess = @*ARGS[0];
my Int $rotate = @*ARGS[1].Int;

say qq|"$mess" rotated $rotate characters gives "{rotate($mess,$rotate)}".|;

I would like to see how the rest of you can code this algorithm using Perl 6 and the gifts so far. After all, the language can only get better with more usage.

Day 7: Looping for fun and profit

Day 7: Looping for fun and profit

Any programmer who’s ever used a language which has them probably knows that loops are incredibly useful. In languages which provide them, foreach loops for iterating over arrays or lists tend to end up being very common. In Perl 5, these loops were provided by the foreach keyword, although you could also write for, sharing a keyword with the more general C-style for loops.

In Perl 6, that’s all changed.

for is now exclusively for iterating over lists. foreach has disappeared, and C-style for loops are handled by the new keyword loop. We’re not going to discuss those today, but we are going to focus on the new for loop, which combines with some other Perl 6 language features to deliver an enormously flexible and powerful construct.

Let’s look at a basic case.

for 1, 2, 3, 4 { .say }

There some immediately noticeable things about the syntax here. There are no brackets around the list construction, which is something that extends throughout Perl 6. Generally, you need a lot fewer brackety characters than in Perl 5. Much like in Perl 5, the loop variable is $_ by default. The method call of say with no invocant is the same as saying $_.say. Note that in Perl 6, you cannot say say with no argument to default to $_, you have to use the .say form, or specify $_ explicitly.

The block doesn’t have to be an ordinary block. It can be a pointy block, which lets you name your loop variable using the pointy block’s parameter capability.

for 1, 2, 3, 4 -> $i { $i.say }

A pointy block is a bit like an anonymous subroutine, except it doesn’t catch return exceptions. If you call return inside a pointy block, the enclosing routine will return.

Pointy blocks can take more than one parameter in their parameter lists. What happens if you do that?

for 1, 2, 3, 4 -> $i, $j { "$i, $j".say }

Well, if you run it, you get:

1 2
3 4

So what’s actually happened is that you’ve iterated over the list two elements at a time. This works for any number of parameters, with the minimum of one, degenerating to using $_ if you provide no explicit parameters yourself.

Having realised we can do this, what can we do with the generation of the list we iterate over? Well of course, we can use an array variable:

for @array { .say }

Although in many simple cases, we might prefer to use map: *.say;

Or a hyperoperator, if order and sequentiality isn’t important:


But neither of those things are today’s subject.

We might generate a list of numbers using the range constructor &infix:<..>:

for 1..4 { .say }

It’s very common that we want to generate a list of $n numbers beginning with 0, such as array indicies. We could write 0..$n-1, or using a variant of the range constructor 0..^$n, but Perl 6 provides a handy shortcut in the form of prefix:<^>:

for ^4 { .say }

Which will output:


One reason people often fall back on C-style for loops in Perl 5 is because they need to know what index in the array they are at for each item, or because they need to iterate over two or more arrays in parallel. Perl 6 offers a shortcut here, with the infix:<Z> zip operator.

for @array1 Z @array2 -> $one, $two { ... }

Assuming the two arrays are the same length, $one will be each element of @array1 and $two will be the corresponding element of @array2. If they are different lengths, iteration will stop when the end of the shorter array is reached.

With this knowledge, and the awareness that Perl 6 has lazy list generators, we can easily include the array index in the iteration:

for ^Inf Z @array -> $index, $item { ... }

Although if infinite lists make you nervous,

for ^@array.elems Z @array -> $index, $item { ... }

will give you the same results, but the most elegant presentation is probably:

for @array.kv -> $index, $item { ... }

@array.kv returns the keys and values interleaved, where the keys of an array are the element indices, so iterating over them two at a time has the desired effect.

Hopefully this post has given you an idea of the flexibility inherent in Perl 6’s for loops and how easy they can be to use for a variety of common tasks. Before we part, I’m going to answer one final question I know somebody’s been thinking.

What, you ask, if I want to iterate over four arrays at once?

for @one Z @two Z @three Z @four -> $one, $two, $three, $four { ... }

That’s a list associative infix operator, that is. Enjoy.

Day 6: Going Into Hyperspace

Day 6: Going Into Hyperspace

pmichaud introduced Perl 6’s hyper operators yesterday. I’d like to explore these powerful meta operators further.

First, for simplicity I’m going to code a helper function, lsay, to easily get nice-looking output of lists. The sub is created using our so you can use it on the REPL.

our sub lsay(@a) { @a.perl.say }

Then we can start looking at hyperoperator examples. For this post I’m going to use >> and << instead of » and «, mostly because they are easier on my eyes. (I’m afraid I may need to get glasses.) » and « are generally considered the true form of the operator, but the longer ASCII version will work as well.

First, the most basic: adding two lists of the same length:

> lsay (1, 2, 3, 4) <<+>> (3, 1, 3, 1)
[4, 3, 6, 5]
> lsay (1, 2, 3, 4) >>+<< (3, 1, 3, 1)
[4, 3, 6, 5]

If the lengths of the arrays are the same, there’s no difference between the two forms. But if the length is different:

> lsay (1, 2, 3, 4) <<+>> (3, 1)
[4, 3, 4, 5]
> lsay (1, 2, 3, 4) >>+<< (3, 1)
Sorry, right side is too short and not dwimmy.

The rule is that whatever is pointed to by the pointy end of the hyperoperator can be extended if it is shorter than the other end; it is extended by repeating the last element of that list. Whatever is at the blunt end of the hyperoperator cannot be extended. All combinations are allowed, so you can specify that only the left side can be extended (<<+<<), only the right side (>>+>>), both sides can be extended (<<+>>), or neither side can be extended (>>+<<). Single scalars extend as well:

> lsay (1, 2, 3, 4) >>+>> 2
[3, 4, 5, 6]
> lsay 3 <<+<< (1, 2, 3, 4)
[4, 5, 6, 7]

So that’s the basics of using hyperoperator with an infix operator. You can also use them with prefix and postfix operators:

> lsay ~<<(1, 2, 3, 4)
["1", "2", "3", "4"]
> my @a= (1, 2, 3, 4); @a>>++; lsay @a;
[2, 3, 4, 5]

You can also:

> lsay (0, pi/4, pi/2, pi, 2*pi)>>.sin
[0, 0.707106781186547, 1, 1.22464679914735e-16, -2.44929359829471e-16]
> lsay (-1, 0, 3, 42)>>.Str
["-1", "0", "3", "42"]

That is to say >>. works to call a method on every member of the list.

However much you are tempted to write @array>>.say, don’t do it. It may work in the current version of Rakudo, but by using the hyper operator you are promising the operation is parallelizable, and the order of the operations on the list(s) is not fixed. The hope is that future versions of Perl 6 will automatically run these operations in parallel.

Other quick notes: The hyperoperators don’t just work with the built-in set of operators. They will work with any new operator you define as well. (That works now in Rakudo, mostly.) They will work with the in-place operators, e.g. @a >>/=>> 2 to divide an entire array by 2. (This does not work in current Rakudo.) They will work with multi-dimensional lists, with trees, and with hashes; see S03 Hyper operators. (As far as I know, these do not yet work in Rakudo either.)

I don’t know too many examples yet of source code using hyperoperators extensively, though LastOfTheCarelessMen’s Vector class is a good if straightforward start — it implements an N-dimensional vector class without a single explicit loop.

Day 5: Metaoperators

Day 5: Metaoperators

In the Day 4 box, we saw an interesting implementation for the factorial function:

    sub fac(Int $n) {
        [*] 1..$n

Okay, so how does that work? Opening up today’s Advent box provides some answers!

Perl 6 has a number of different “meta operators” that modify the existing operators to perform more powerful functions.

The square brackets about are an example of the “reduce metaoperator”; they cause an infix operator to become a list operator that acts as though the infix was placed between each pair of elements. For example, the expression

    [+]  1, $a, 5, $b

is essentially the same as writing

    1 + $a + 5 + $b

This gives us a handy mechanism to “sum all elements in a list”:

    $sum = [+] @a;            # sum all elements of @a

Most of the infix operators (including user-defined operators) can be placed inside of square brackets to turn them into reductions:

    $prod = [*] @a;           # multiply all elements of @a

    $mean = ([+] @a) / @a;    # calculate mean of @a

    $sorted = [<=] @a;        # true if elements of @a are numerically sorted

    $min = [min] @a, @b;      # find the smallest element of @a and @b combined

So, in the factorial subroutine above, the expression [*] 1..$n returns the product of multiplying all of 1 through $n together.

Another useful metaoperator is the “hyper” operator. Placing »
and/or « (or the ASCII >> and << equivalents) next to an operator makes it “hyper”, which causes it operate on elements of lists. For example, the following calculates @c as the pairwise addition of the elements in @a and @b:

    @c = @a »+« @b;

In Perl 5, we’d generally write something like

    for ($i = 0; $i < @a; $i++) {
        $c[$i] = $a[$i] + $b[$i];

which is quite a bit longer.

As with the square brackets above, we can use hyper on a variety of operators, including user-defined operators:

    # increment all elements of @xyz

    # each element of @x is the smaller of @a and @b
    @x = @a »min« @b;

We can also flip the angles to enable a scalar to act like an array:

    # multiply each element of @a by 3.5
    @b = @a »*» 3.5;

    # multiply each element of @x by $m and add $b
    @y = @x »*» $m »+» $b;

    # invert all elements of @x
    @inv = 1 «/« @x;

    # concatenate @last, @first to produce @full
    @full = (@last »~» ', ') »~« @first;

Of course, reductions and hyper operators can be combined in expressions:

    # calculate the sum of squares of @x
    $sumsq = [+] ( @x »**» 2);

There are many other metaoperators available, including X (cross), R (reverse), S (sequential). In fact, the “in-place” operators such as +=, *=, ~=, are just meta forms created by suffixing an operator with an equals sign:

    $a += 5;      # same as $a = $a + 5;
    $b //= 7;     # same as $b = $b // 7;
    $c min= $d;   # same as $c = $c min $d;