Sign In/My Account | View Cart  
advertisement


Listen Print Discuss

Everyday Perl 6
by Jonathan Scott Duff | Pages: 1, 2

Idioms

Another big change is that some of the standard Perl 5 idioms look different in Perl 6. In particular, the standard idiom for reading lines from a file involves a for loop rather than a while loop:

    # Perl 6                        # Perl 5
    for =$fh { ... }                while (<$fh>) { ... }
    for =<>  { ... }                while (<>)    { ... }

The Perl 5 programmers are probably thinking, "but doesn't that put the part that reads the filehandle in list context, causing the entire file to be slurped into memory?" The answer is both yes and no. Yes, it's in list context, but in Perl 6, by default all lists are lazy so they aren't read until necessary.

In this example, unary = is the operator that causes an iterator to, well...iterate. If $fh is a filehandle, =$fh iterates over that file by reading one line at a time. In scalar context =$fh will read one line, and in list context it will read one line at a time as many times as necessary to get to the end of the file. Iterating over the empty string (remember the new role of the angle brackets) is equivalent to Perl 5's reading files from the command line.

Operator Rename

Several common operators have new symbols in Perl 6. These symbol changes make the overall language more regular so that it's easier to parse, but most importantly so that it's easier for humans to remember:

    # Perl 6                        # Perl 5
    $object.method(@args);          $obj->method(@args);
    $x = $cond ?? $true !! $false;  $x = $cond ? $true : $false;
    $s = "con" ~ "cat" ~ "enate";   $s = "con" . "cat" . "enate";
    $str ~~ /$pattern/;             $str =~ /$pattern/;

Any time you see a ~ in Perl 6, it has something to do with strings. A unary ~ puts its rvalue in a string context, binary ~ is string concatenation, and a doubled ~ lets you match a regular expression against a string (actually, it does more than that, but from a perspective of not knowing the language at all or from knowing Perl 5, it's enough to know initially that ~~ will pattern match on strings).

New Perl 6 Syntax

Perl 6 also has some brand-new syntax.

Long Comments

Many people always gripe about the fact that Perl 5 lacks a lightweight multi-line comment mechanism (POD is apparently too verbose). Perl 6 solves this one quite nicely. If a bracketing character immediately follows the comment character (#), the comment extends to the corresponding closing bracket.

    #[  This is a
        multi-line comment
        that ends here ---->  ]

See Whitespace and Comments in Synopsis 02 for more information.

switch Statement

For those of you who have forever wished for a switch statement in Perl, Perl 6 will have it (only by another name):

    given $thing {
        when 3      { say "three"; }
        when 5      { say "five";  }
        when 9      { say "nine";  }
        when "a"    { say "what?"; }
        default     { say "none";  }
    }

This construct is much more powerful than I've outlined here, however, as it takes advantage of the smart match operator to do the right thing when the given $thing (or the thing it's being "compared" against in the when clause) is an object or an array or hash, or code, etc.

New Loops

The C-style for loop operator has become loop. But you can omit the parenthetical portion to write an infinite loop:

    loop { ... }

Another new looping construct is the repeat loop, which occupies the same niche as Perl 5's do-while pseudoloop. The big difference is that unlike do-while, repeat is a real loop and as such, you are free to use next, last, redo and it does the right thing.

For more information see Synopsis 04.

Parameterized Blocks

Essentially, every block in a Perl 6 program is a subroutine. Some blocks, like those used in an if statement, have no parameters; but others do, such as the body of a for loop. But any block may be parameterized. This is especially useful for doing things that aren't easy in Perl 5 but should be -- like examining values three at a time with map:

    my @trimults = map -> $a,$b,$c { $a * $b * $c }, @numbers;

Here is an example where Perl 6 co-opts the arrow notation for a higher purpose. The arrow now introduces parameters to a block. You are most likely to see this in for loops:

    # Perl 6                        # Perl 5
    for @array -> $a     { ... }    for my $a (@array) { ... }
    for @array -> $a, $b { ... }    # too complex :)

The second for loop will take items from @array two at a time and lexically assign them to $a and $b for the duration of the block. The same behavior is not so easy to accomplish in Perl 5.

Another way to write the @trimults example, but slightly less verbose, is:

    my @trimults = map { $^a * $^b * $^c }, @numbers;

Variables with a caret (^) immediately after the sigil are implicit parameters to the block, and Perl 6 assigns them in Unicode-order. That is, $^a is the first parameter, $^b the second, and $^c the third.

There is yet a third way to write a parameterized block that's more verbose but more also powerful. It allows the programmer to take full advantage of subroutine signatures. Yes, TMTOWTDI, is still alive and well :-)

Subroutine Signatures

You can still write subroutines the way you always have in Perl 5, but Perl 6 allows you to specify a "signature" that describes how many parameters to pass to the subroutine, which parameters are optional, which parameters are positional, which are named, what the default values are for unpassed parameters, which parameters copy the value that is passed, which parameters alias the variable, etc.

For more information on subroutines in Perl 6, see Synopsis 06 and Phil Crow's recent article The Beauty of Perl 6 Parameter Passing.

Variable Typing

In the interest of allowing programmers to be precise in their expressions, Perl 6 allows for optional variable typing. That is, the programmer can not only say, "this variable is a scalar" but can also say "this scalar conforms to the expectation of items in this particular class." In other words, you can say things such as:

    my Dog  $spot;
    my Fish $wanda;

...and it means something useful to Perl as well as the programmer. The variable $spot is only usable in a place where Perl expects a Dog, and the variable $wanda only works in places where Perl expects a Fish. However, the Perl 5-ish code will work perfectly fine, too:

    my Dog  $spot;
    my Fish $wanda;
    my $x;
    $x = $spot;
    $x = $wanda;

...because $x is sufficiently "untyped" that it can accept a Dog or a Fish, or any scalar thing.

Multiple Dispatch

Variable typing coupled with subroutine signatures gives the benefit of multiple dispatch. What that means is that you can declare two subroutines with the same name but different signatures, and Perl will select which subroutine to invoke at runtime based on the parameters sent to the subroutine. For example:

    multi sub feed(Dog  $spot)  { say "dog food!";  }
    multi sub feed(Fish $wanda) { say "fish food!";  }

    my Fish $nemo;
    my Dog  $rover;

    feed($nemo);                 # fish food!
    feed($rover);                # dog food!

The multi keyword tells Perl that you intend to declare multiple subroutines with the same name, and it should use the name and the parameters and whatever other distinguishing characteristics it can to decide which one to actually invoke.

The End

I hope this introduction gives you a feel for some of the changes in Perl 6 and shows how these changes are good and useful.

A prototype implementation of Perl 6 called pugs should be able to execute all of the examples I've given in this article. If not, get on the freenode IRC network, join #perl6, ask for a commit bit, and submit a test to the Pugs repository, and one of the pugs Developers will probably update Pugs to run it soon enough :-)

Thanks

Special thanks to all of the people on IRC (#perl and #perl6) who looked over this article and gave their input and commentary.