Perl6::Bible::S03.3pm

Langue: en

Autres versions - même langue

Version: 2006-02-28 (fedora - 01/12/10)

Section: 3 (Bibliothèques de fonctions)

TITLE

Synopsis_03 - Summary of Perl 6 Operators

AUTHOR

Luke Palmer <luke@luqui.org>

VERSION

   Maintainer: Larry Wall <larry@wall.org>
   Date: 8 Mar 2004
   Last Modified: 25 Feb 2006
   Number: 3
   Version: 13
 
 

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, "X...X". 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.
*
The backslash operator still produces a reference, but when applied to a parenthesized list, produces a List object (an arglist) instead of a list of refs. (According to the previous item, in scalar context the backslash is redundant, but is good documentation anyway.)
*
The old scalar ".." flipflop operator is now done with "ff" operator. (".." now always produces a Range object even in scalar context.) The "ff" operator may take a caret on either end to exclude either the beginning or ending. There is also a corresponding "fff" operator with Perl 5's "..." semantics.

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 "===" tests type and value correspondence: for two value types, tests whether they are the same value (eg. "1 === 1"); for two reference types, checks whether they have the same identity value. For reference types that do not define an identity, the reference itself is used (eg. it is not true that "[1,2] === [1,2]", but it is true that "\@a === \@a"). Any reference type may pretend to be a value type by defining a ".id" method. (It may also overload "infix:<===>" for more efficient comparison of any two objects of that type, but it had better return the same result as if the two identity values had been generated and compared.) Two values are never equivalent unless they are of exactly the same type. By contrast, "eq" always coerces to string, while "==" always coerces to numeric. In fact, "$a eq $b" really means ""~$a === ~$b"" and "$a == $b" means ""+$a === +$b".

Note also that, while string hashes use "eq" semantics by default, object hashes use "===" semantics.

*
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. Its precedence is now equivalent to assignment, and it is right associative.
*
"^^" 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. (To catch ``brainos'', the Perl 6 parser defines an "infix:<=~>" macro which always fails at compile time with a message directing the user either to use "~~" or "~=" instead, or to put a space between if they really wanted to assign a stringified value.)
*
Unary "." calls its single argument (which must be a method, or a dereferencer for a hash or array) on $_.
*
The ".." range operator has variants with "^" on either end to indicate exclusion of that endpoint from the range. It always produces a Range object. Range objects are lazy iterators, and can be interrogated for their current ".min" and ".max" values (which change as they are iterated). Ranges are not autoreversing: 2..1 is always a null range, as is "1^..^2". To reverse a range use:
     2..1:by(-1)
     reverse 1..2
 
 

(The "reverse" is preferred because it works for alphabetic ranges as well.)

Because "Range" objects are lazy, they do not automatically generate a list. So smart matching against a Range object smartmatches the endpoints in the domain of the object being matched, so "1.5 ~~ 1^..^2" is true. (But "2.1 ~~ 1..2" is false.)

*
The unary "^" operator generates a range from 0 up to one less than its argument. so "^4" is short for "0..^4" or 0..3.
     for ^4 { say $_ } # 0, 1, 2, 3
 
 
*
"..." 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 (by calling "fail") if it is ever executed. Variant "???" calls "warn", and "!!!" calls "die".
*
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. The ".^" operator calls a class metamethod.
*
Unary "=" reads lines from a filehandle or filename, or in general iterates an iterator.

Hyper operators

The Unicode characters "X" ("\x[BB]") and "X" ("\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) X+X (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 = -X @positives;
 
      @positions X++;            # Increment all positions
 
      @objects X.run();
      ("f","oo","bar")X.chars;   # (1,2,3)
 
 

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

Hyper operators are defined recursively on array references, so:

     -X [[1, 2], 3]               #    [-X[1, 2], -X3]
                                  # == [[-1, -2], -3]
     [[1, 2], 3] X+X [4, [5, 6]]  #    [[1,2] X+X 4, 3 X+X [5, 6]]
                                  # == [[5, 6], [8, 9]]
 
 

Reduction operators

The other metaoperator in Perl 6 is the reduction operator. Any binary operator can be surrounded by square brackets in term position to create a list operator that reduces using that operation:
     [+] 1, 2, 3;      # 1 + 2 + 3 = 6
     my @a = (5,6);
     [*] @a;           # 5 * 6 = 30
 
 

The reduction associates the same way as the operator used:

     [-] 4, 3, 2;      # 4-3-2 = (4-3)-2 = -1
     [**] 4, 3, 2;     # 4**3**2 = 4**(3**2) = 262144
 
 

For list-associating operators (like "<"), all arguments are taken together, just as if you had written it out explicitly:

     [<] 1, 3, 5;      # 1 < 3 < 5
 
 

If no arguments are given, the operator calls "fail" (returning "undef", or throwing an exception if "use fatal" is in effect). If exactly one argument is given, it is returned by default. However, this default doesn't make sense for an operator like "<" that doesn't return the same type as it takes, so these kinds of operators overload the single-argument case to return something more meaningful. All the comparison operators return truth in this case.

This metaoperator can also be used on the semicolon second-dimension separator:

     [[;] 1,2,3]   # equivalent to [1;2;3]
 
 

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 (or List) into the List being constructed for the current call, 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;
 
 

as is this:

     my $args = \(@foo, @bar);    # construct List object
     push *$args;
 
 

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 it 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 "<>", ".<>", "XX", and ".XX" 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';
 
 

A colon may also be used on an ordinary method call to indicate that it should be parsed as a list operator:

     $hacker.feed: 'Pizza and cola';
 
 

zip

In order to support parallel iteration over multiple arrays, Perl 6 has a "zip" function that builds tuples of 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 "X".

To read arrays in parallel like "zip" but just sequence the values rather than generating tuples, use "each" instead of "zip".

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

The "each" function reads to the end of the longest list, not counting lists that are known to be infinite such as "0..Inf". Missing values are replaced with "undef". In contrast, use "roundrobin" if you just wish to skip missing entries:

     for roundrobin(@queue1; @queue2; @queue3) -> $next {
         ...
     }
 
 

To read arrays serially rather than in parallel, use "cat(@x;@y)".

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 (which is fewer than Perl 5):
     terms               42 "eek" $x /abc/ (1+2) a(1) :by(2) .meth listop
     method postfix      . .+ .? .* .() .[] .{} .XX .=
     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 <=> .. ^.. ..^ ^..^ ff ^ff ff^ ^ff^ fff ^fff etc.
     chaining binary     != == < <= > >= ~~ !~ eq ne lt le gt ge =:= ===
     tight and           &&
     tight or            || ^^ //
     ternary             ?? !!
     assignment          = := ::= += -= **= xx= etc. (and also =>)
     list item separator , X
     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