TITLE

Synopsis 3: Summary of Perl 6 Operators

AUTHOR

Luke Palmer <luke@luqui.org>

VERSION

Maintainer: Larry Wall <larry@wall.org>
Date: 8 Mar 2004
Last Modified: 22 Feb 2005
Number: 3
Version: 5

Operator renaming

Several operators have been given new names to increase clarity and better Huffman-code the language:

  • -> becomes ., like the rest of the world uses.

  • The string concatenation . becomes ~. Think of it as "stitching" the two ends of its arguments together.

  • Unary ~ now imposes a string context on its argument, and + imposes a numeric context (as opposed to being a no-op in Perl 5). Along the same lines, ? imposes a boolean context, and * imposes a list context.

  • Bitwise operators get a data type prefix: +, ~, or ?. For example, | becomes either +| or ~| or ?|, depending on whether the operands are to be treated as numbers, strings, or boolean values. Left shift << becomes +< , and correspondingly with right shift. Unary ~ becomes either +^ or ~^ or ?^, since a bitwise NOT is like an exclusive-or against solid ones. Note that ?^ is functionally identical to !. ?| differs from || in that ?| always returns a standard boolean value (either 1 or 0), whereas || return the actual value of the first of its arguments that is true.

  • x splits into two operators: x (which concatenates repetitions of a string to produce a single string), and xx (which creates a list of repetitions of a list or scalar).

  • Trinary ? : becomes ?? ::.

  • qw{ ... } gets a synonym: < ... >, and an interpolating variant, «...». For those still living without the blessings of Unicode, that can also be written: << ... >>.

  • The scalar comma , now constructs a list reference of its operands. You have to use a [-1] subscript to get the last one.

New operators

  • Binary // is just like ||, except that it tests its left side for definedness instead of truth. There is a low-precedence form, too: err.

  • Binary => is no longer just a "fancy comma." It now constructs a Pair object that can, among other things, be used to pass named arguments to functions. It provides scalar context to both sides.

  • ^^ is the high-precedence version of xor.

  • =~ becomes the "smart match" operator ~~, with a whole new set of semantics. Anywhere you used =~ before you now use ~~, but ~~ is much more general now. See "Synopsis 4" for details.

  • Unary . calls its single argument (which must be a method, or an dereferencer for a hash or array) on $_.

  • The .. binary range operator has variants with ^ on either end to indicate exclusion of that endpoint from the range.

  • ... is a unary postfix operator that constructs a semi-infinite (and lazily evaluated) list, starting at the value of its single argument.

  • However, ... as a term is the "yada, yada, yada" operator, which is used as the body in function prototypes. It complains bitterly if it is ever executed.

  • In addition, to the ordinary . method invocation, there are variants .*, .?, and .+ to control how multiple parent methods of the same name are handled. The .= operator does inplace modification of the object on the left.

  • Unary = reads lines from a filehandle or filename, or in general iterates an iterator.

Hyper operators

The Unicode characters » (\x[BB]) and « (\x[AB]) and their ASCII digraphs >> and << are used to denote "list operations", which operate on each element of two lists (or arrays) and return a list (or array) of the results. Spaces are not allowed on the "pointy" end of each "hyper", but are allowed on the blunt end. For example:

(1,1,2,3,5) »+« (1,2,3,5,8);  # (2,3,5,8,13)

If one argument is insufficiently dimensioned, Perl "upgrades" it:

(3,8,2,9,3,8) >>-<< 1;          # (2,7,1,8,2,7)

When using a unary operator, only put it on the operand's side:

@negatives = -« @positives;

@positions »++;            # Increment all positions

@objects ».run();
("f","oo","bar")».length;   # (1,2,3)

Note that method calls are really postfix operators, not infix, so you shouldn't put a « after the dot.

Junctive operators

|, &, and ^ are no longer bitwise operators (see "Operator Renaming") but now serve a much higher cause: they are now the junction constructors.

A junction is a single value that is equivalent to multiple values. They thread through operations, returning another junction representing the result:

1|2|3 + 4;                              # 5|6|7
1|2 + 3&4;                              # (4|5) & (5|6)

Note how when two junctions are applied through an operator, the result is a junction representing the operator applied to each combination of values.

Junctions come with the functional variants any, all, one, and none.

This opens doors for constructions like:

unless $roll == any(1..6) { print "Invalid roll" }

if $roll == 1|2|3 { print "Low roll" }

Junctions work through subscripting:

print if @foo[any(1,2,3)]

Junctions are specifically unordered. So if you say

for all(@foo) {...}

it indicates to the compiler that there is no coupling between loop iterations and they can be run in any order or even in parallel.

Chained comparisons

Perl 6 supports the natural extension to the comparison operators, allowing multiple operands.

if 3 < $roll <= 6              { print "High roll" }

if 1 <= $roll1 == $roll2 <= 6  { print "Doubles!" }

Note: any operator beginning with < must have whitespace in front of it, or it will be interpreted as a hash subscript instead.

Binding

A new form of assignment is present in Perl 6, called "binding," used in place of typeglob assignment. It is performed with the := operator. Instead of replacing the value in a container like normal assignment, it replaces the container itself. For instance:

my $x = 'Just Another';
my $y := $x;
$y = 'Perl Hacker';

After this, both $x and $y contain the string "Perl Hacker," since they are really just two different names for the same variable.

There is another variant, spelled ::=, that does the same thing at compile time.

There is also an identity test, =:=, which tests whether two names are bound to the same underlying variable. $x =:= $y would return true in the above example.

List flattening

Since typeglobs are being removed, unary * may now serve as a lazy list flattening operator. It is used to "flatten" an array into a list, usually to allow the array's contents to be used as the arguments of a subroutine call. Note that those arguments still must comply with the subroutine's signature, but the presence of * defers that test until run time for that argument (and for any subsequent arguments):

my @args = (\@foo, @bar);
push *@args;

is equivalent to:

push @foo, @bar;

In list context, a scalar reference to an array does not flatten. Hence

$bar = @bar;
push @foo, $bar;

merely pushes a single scalar reference onto @foo. You can explicitly flatten it in any of these ways:

push @foo, *$bar;
push @foo, @$bar;
push @foo, $bar[];

(The * in list context doesn't change the call semantics as is does in scalar context.) Note that these three forms also allow you to specify list context on assignment:

*$bar = (1,2,3);
@$bar = (1,2,3);
$bar[] = (1,2,3);

The last is particularly useful at the end of a long name naming an array attribute:

$foo.bar.baz.bletch.whatever.attr[] = (1,2,3)

The empty [] and .[] postfix operators are interpreted as zero-dimensional slices returning the entire array, not null slices returning no elements. Likewise for {} and .{} on hashes, not to mention the <>, .<>, «», and .«» constant and interpolating slice subscripting forms.

The * operator flattens lazily. To get an immediate flattening like Perl 5 does, use unary ** instead. You may use either of them on a scalar iterator to force it to iterate.

Piping operators

The new operators ==> and <== are akin to UNIX pipes, but work with functions that accept and return lists. For example,

@result = map { floor($^x / 2) }
            grep { /^ \d+ $/ }
              @data;

Can also now be written:

@data ==> grep { /^ \d+ $/ }
      ==> map { floor($^x / 2) }
      ==> @result;

or:

@result <== map { floor($^x / 2) }
        <== grep { /^ \d+ $/ }
        <== @data;

Either form more clearly indicates the flow of data. See "Synopsis 6" for more of the (less-than-obvious) details on these two operators.

Invocant marker

An appended : marks the invocant when using the indirect-object syntax for Perl 6 method calls. The following two statements are equivalent:

$hacker.feed('Pizza and cola');
feed $hacker: 'Pizza and cola';

zip

In order to support parallel iteration over multiple arrays, Perl 6 has a zip function that interleaves the elements of two or more arrays.

for zip(@names, @codes) -> $name, $zip {
    print "Name: $name;   Zip code: $zip\n";
}

zip has an infix synonym, the Unicode operator ¥.

Minimal whitespace DWIMmery

Whitespace is no longer allowed before the opening bracket of an array or hash accessor. That is:

%monsters{'cookie'} = Monster.new;  # Valid Perl 6
%people  {'john'}   = Person.new;   # Not valid Perl 6

One of the several useful side-effects of this restriction is that parentheses are no longer required around the condition of control constructs:

if $value eq $target {
    print "Bullseye!";
}
while 0 < $i { $i++ }

It is, however, still possible to align accessors by explicitly using the . operator:

%monsters.{'cookie'} = Monster.new;
%people  .{'john'}   = Person .new;
%cats    .{'fluffy'} = Cat    .new;

Precedence

Perl 6 has 22 precedence levels (fewer than Perl 5):

terms		42 "eek" $x /abc/ (1+2) a(1) :by(2) .meth listop
method postfix	. .+ .? .* .+ .() .[] .{} .«» .=
autoincrement	++ --
exponentiation	**
symbolic unary	! + - ~ ? * ** +^ ~^ ?^ \
multiplicative	* / % x xx +& +< +> ~& ~< ~>
additive		+ - ~ +| +^ ~| ~^
junctive and (all)	&
junctive or (any)	| ^
named unary		rand sleep abs etc.
nonchaining binary	=> but does cmp <=> .. ^.. ..^ ^..^
chaining binary	!= == < <= > >= ~~ !~ eq ne lt le gt ge =:=
tight and		&&
tight or		|| ^^ //
ternary		?? ::
assignment		= := ::= += -= **= xx= etc.
list item separator	, ¥
list op (rightward)	<== print push any all true not etc.
pipe forward	==>
loose and		and
loose or		or xor err
expr terminator	; {} as control block, statement modifiers

1 POD Error

The following errors were encountered while parsing the POD:

Around line 54:

Non-ASCII character seen before =encoding in 'C<«...»>.'. Assuming UTF-8