Synopsis 3: Perl 6 Operators
Luke Palmer <luke@luqui.org>
Maintainer: Larry Wall <larry@wall.org> Date: 8 Mar 2004 Last Modified: 2 Apr 2008 Number: 3 Version: 135
For a summary of the changes from Perl 5, see "Changes to Perl 5 operators".
From t/operators/precedence/builtins.t lines 12–186 (46 √, 2 ×): (skip)
| L<S03/Operator precedence> |
| |
| =cut |
| |
| plan 48; |
| |
| |
| # terms |
| |
| # FIXME how do we test this? |
| |
| # postfix method |
| |
| my @a = 1,2,3; |
√ | is(++@a[2], 4, "bare postfix binds tighter than ++"); |
√ | is(++@a.[2], 5, "dotted postfix binds tighter than ++"); |
| |
| # autoincrement |
| |
| my $i = 2; |
√ | is(++$i ** 2, 9, "++ bind tighter than **"); |
√ | is(--$i ** 2, 4, "-- does too"); |
| |
| # exponentiation |
| |
√ | is(-2**2, -4, "** bind tighter than unary -"); |
√ | isa_ok(~2**4, "Str", "~4**4 is a string"); |
| |
| # symbolic unary |
| |
√ | is(!0 * 2, 2, "unary ! binds tighter than *"); |
√ | is(!(0 * 2), 1, "beh"); |
√ | is(?2*2, 2, "binary -> numify causes reinterpretation as, binds tighter than *"); |
| |
| # multiplicative |
| |
√ | is(4 + 3 * 2, 10, "* binds tighter than binary +"); |
√ | is(2 - 2 / 2, 1, "/ binds tighter than binary -"); |
| |
| # additive |
| |
√ | is(1 ~ 2 * 3, 16, "~ binds looser than *"); |
√ | ok((1 ~ 2 & 12) == 12, "but tighter than &"); |
√ | ok((2 + 2 | 4 - 1) == 4, "and + binds tighter than |"); |
| |
| # replication |
| |
√ | is(2 x 2 + 3, "22222", "x binds looser than binary +"); |
√ | is((2 x 2) + 3, 25, "doublecheck"); |
| |
| # concatenation |
| |
√ | is(2 x 2 ~ 3, "223", "x binds tighter than binary ~"); |
√ | ok((2 ~ 2 | 4 ~ 1) == 41, "and ~ binds tighter than |"); |
| |
| # junctive and |
| |
√ | ok( (1 & 2 | 3) !=3, '& binds tighter than |'); |
√ | ok((!(1 & 2 | 3) < 2), "ditto"); |
√ | ok(((1 & 2 ^ 3) < 3), "and also ^"); |
√ | ok( !(1 & 2 ^ 4) != 3, "blah blah blah"); |
| |
| # junctive or |
| |
| { # test that | and ^ are on the same level |
| my $a = (1 | 2 ^ 3); |
| my $b = (1 ^ 2 | 3); |
| |
√ | ok($a == 3, "only one is eq 3"); |
√ | ok($a != 3, "either is ne 3"); |
√ | ok($a == 1, "either is eq 1"); |
√ | ok($b == 2, "either is eq 2, ne 3"); |
√ | ok($b == 1, "either is eq 1"); |
√ | ok($b == 3, "either is eq 3, of which only one is"); |
√ | ok(!($b != 3), "1 is ne 3, and (2 | 3) is both ne 3 and eq 3, so it's ne, so 1 ^ 2 | 3"); |
| }; |
| |
| { |
| my $a = (abs -1 ^ -1); # read as abs(-1 ^ -1) -> (1^1) |
√ | ok(!($a == 1), 'junctive or binds more tightly then abs (1)'); |
| |
| my $b = ((abs -1) ^ -1); # -> (1 ^ -1) |
√ | ok($b == 1, "this is true because only one is == 1"); |
| }; |
| |
| # named unary |
| |
√ | is((abs -1 .. 3), (1 .. 3), "abs binds tighter than .."); |
√ | is((rand 3 <=> 5), -1, "rand binds tighter than <=>"); |
| |
| # nonchaining |
| |
√ | ok(0 < 2 <=> 1 < 2, "0 < 2 <=> 1 < 2 means 0 < 1 < 2"); |
| |
| # chaining |
| |
√ | is((0 != 1 && "foo"), "foo", "!= binds tighter than &&"); |
√ | ok((0 || 1 == (2-1) == (0+1) || "foo") ne "foo", "== binds tighter than || also when chaning"); |
| |
| # tight and (&&) |
| |
| # tight or (||, ^^, //) |
| |
√ | is((1 && 0 ?? 2 !! 3), 3, "&& binds tighter than ??"); |
| ### FIXME - need also ||, otherwise we don't prove || and ?? are diff |
| |
| # conditional |
| |
| { |
| my $a = 0 ?? "yes" !! "no"; |
√ | is($a, "no", "??!! binds tighter than ="); |
| # (my $b = 1) ?? "true" !! "false"; |
| # is($b, 1, "?? !! just thrown away with = in parens"); |
| }; |
| |
| |
| # item assignment |
| |
| { |
| my $c = 1, 2, 3; |
√ | is($c, 1, "$ = binds tighter than ,"); |
| my $a = (1, 3) X (2, 4); |
√ | is($a, [1, 3], "= binds tighter than X"); |
| }; |
| |
| # loose unary |
| |
| my $x; |
√ | is((true $x = 42), 1, "item assignment is tighter than true"); |
| |
| # comma |
| |
√ | is(((not 1,42)[1]), 42, "not is tighter than comma"); |
| |
| # list infix |
| |
| { |
| my @d; |
√ | ok eval('@d = 1,3 Z 2,4'), "list infix tighter than list assignment, looser t than comma"; |
× | is(@d, [1 .. 4], "to complicate things further, it dwims", :todo); |
| } |
| |
| { |
| my @b; |
| eval('@b = ((1, 3) Z (2, 4))'); |
√ | is(@b, [1 .. 4], "parens work around this"); |
| }; |
| |
| # list prefix |
| |
| { |
| my $c; |
| eval('$c = any 1, 2, Z 3, 4'); |
× | ok($c == 3, "any is less tight than comma and Z"); |
| } |
| |
| my @c = 1, 2, 3; |
√ | is(@c, [1,2,3], "@ = binds looser than ,"); |
| |
| # loose and |
| |
| # loose or |
| |
| # terminator |
| |
| # uc|ucfirst|lc|lcfirst |
| # t/builtins/strings/uc|ucfirst|lc|lcfirst.t didn't compile because of this bug. |
| # Compare: |
| # $ perl -we 'print uc "a" eq "A"' |
| # 1 |
| # opposed to Pugs parses it: |
| # $ perl -we 'print uc("a" eq "A")' |
| # $ (no output) |
√ | ok (uc "a" eq "A"), "uc has the correct precedence in comparision to eq"; |
| |
Not counting terms and terminators, Perl 6 has 23 operator precedence levels (same as Perl 5, but differently arranged). Here we list the levels from "tightest" to "loosest", along with a few examples of each level:
A Level Examples
= ===== ========
N Terms 42 3.14 "eek" qq["foo"] $x :!verbose @$array
L Method postfix .meth .+ .? .* .() .[] .{} .<> .«» .:: .= .^ .:
L Autoincrement ++ --
R Exponentiation **
L Symbolic unary ! + - ~ ? | +^ ~^ ?^ \ ^ =
L Multiplicative * / % +& +< +> ~& ~< ~> ?& div mod
L Additive + - +| +^ ~| ~^ ?| ?^
N Replication x xx
L Concatenation ~
X Junctive and &
X Junctive or | ^
L Named unary sleep abs sin
N Nonchaining infix but does <=> leg cmp .. ..^ ^.. ^..^
C Chaining infix != == < <= > >= eq ne lt le gt ge ~~ === eqv !eqv
L Tight and &&
L Tight or || ^^ // min max
L Conditional ?? !! ff fff
R Item assignment = := ::= => += -= **= xx= .=
L Loose unary true not
X Comma operator , p5=>
X List infix Z minmax X X~X X*X XeqvX
R List prefix : print push say die map substr ... [+] [*] any $ @
L Loose and and andthen
L Loose or or xor orelse
N Terminator ; <==, ==>, <<==, ==>>, {...}, unless, extra ), ], }
The associativities specified above are:
Assoc Meaning of $a op $b op $c
===== =========================
L left ($a op $b) op $c
R right $a op ($b op $c)
N non ILLEGAL
C chain ($a op $b) and ($b op $c)
X list op($a, $b, $c) or op($a; $b; $c)
Note that list associativity only works between identical operators. If two different list-associative operators have the same precedence, they are assumed to be left-associative with respect to each other. For example, the X cross operator and the Z zip operator both have a precedence of "list infix", but:
@a X @b Z @c
is parsed as:
(@a X @b) Z @c
If you don't see your favorite operator above, the following sections cover all the operators in precedence order. Basic operator descriptions are here; special topics are covered afterwards.
This isn't really a precedence level, but it's in here because no operator can have tighter precedence than a term. See S02 for longer descriptions of various terms. Here are some examples.
Int literal
42
Num literal
3.14
Str literal
'$100'
Str literal
"Answer = $answer\n"
Str literal
q["$100"]
qq["$answer"]
qq:to/END/
Dear $recipient:
Thanks!
Sincerely,
$me
END
[1,2,3]
Provides list context inside. (Technically, it really provides a "semilist" context, which is a semicolon-separated list of statements, each of which is interpreted in list context and then concatenated into the final list.)
{ }
{ a => 42 }
Inside must be either empty, or a single list starting with a pair or a hash, otherwise you must use hash() or %() instead.
{ ... }
When found where a statement is expected, executes immediately. Othewise always defers evaluation of the inside scope.
\(@a,$b,%c)
An abstraction representing an argument list that doesn't yet know its context.
$x
@y
%z
$^a
$?FILE
@@slice
&func
&div:(Int, Int --> Int)
$()
@()
%()
&()
@@()
/abc/
rx:i[abc]
s/foo/bar/
tr/a..z/A..Z/;
Note ranges use .. rather than -.
Num
::Some::Package
(1+2)
Parentheses are parsed on the inside as a semicolon-separated list of statements, which (unlike the statements in a block) returns the results of all the statements concatenated together as a List of Capture. How that is subsequently treated depends on its eventual binding.
a(1)
:by(2)
:!verbose
:(Dog $self:)
.meth # call on $_
.=meth # modify $_
Note that this may occur only where a term is expected. Where a postfix is expected, it is a postfix. If only an infix is expected (that is, after a term with intervening whitespace), .meth is a syntax error. (The .=meth form is allowed there only because there is a special .= infix assignment operator that is equivalent in semantics to the method call form but that allows whitespace between the = and the method name.)
4,3, sort 2,1 # 4,3,1,2
As in Perl 5, a list operator looks like a term to the expression on its left, so it binds tighter than comma on the left but looser than comma on the right--see List prefix precedence below.
self
undef
rand
All method postfixes start with a dot, though the dot is optional for subscripts. Since these are the tightest standard operator, you can often think of a series of method calls as a single term that merely expresses a complicated name.
See S12 for more discussion of single dispatch method calls.
$obj.meth
$obj.+meth
$obj.?meth
$obj.*meth
In addition to the ordinary . method invocation, there are variants .*, .?, and .+ to control how multiple related methods of the same name are handled.
$obj.::Class::meth
$obj.Class::meth # same thing, assuming Class is predeclared
As in Perl 5, tells the dispatcher which class to start searching from, not the exact method to call.
$obj.=meth
The .= operator does inplace modification of the object on the left.
$obj.^meth
The .^ operator calls a class metamethod; foo.^bar is short for foo.HOW.bar.
$routine.()
$array.[]
$hash.{}
$hash.<>
$hash.«»
The dotless forms of these have exactly the same precedences.
$x.++ # postfix:<++>($x)
$x.:<++> # prefix:<++>($x)
infix:<.> operator, so
$foo . $bar
will always result in a compile-time error indicating the user should use infix:<~> instead. This is to catch an error likely to be made by Perl 5 programmers learning Perl 6.
From t/spec/S03-operators/autoincrement.t lines 9–51 (30 √, 0 ×): (skip)
| #L<S03/Autoincrement precedence> |
| |
| my $base = 10000; |
| |
| my $x = 10000; |
√ | is(0 + ++$x - 1, $base); |
√ | is(0 + $x-- - 1, $base); |
√ | is(1 * $x, $base); |
√ | is(0 + $x-- - 0, $base); |
√ | is(1 + $x, $base); |
√ | is(1 + $x++, $base); |
√ | is(0 + $x, $base); |
√ | is(0 + --$x + 1, $base); |
√ | is(0 + ++$x + 0, $base); |
√ | is($x, $base); |
| |
| my @x; |
| @x[0] = 10000; |
√ | is(0 + ++@x[0] - 1, $base); |
√ | is(0 + @x[0]-- - 1, $base); |
√ | is(1 * @x[0], $base); |
√ | is(0 + @x[0]-- - 0, $base); |
√ | is(1 + @x[0], $base); |
√ | is(1 + @x[0]++, $base); |
√ | is(0 + @x[0], $base); |
√ | is(0 + ++@x[0] - 1, $base); |
√ | is(0 + --@x[0] + 0, $base); |
√ | is(@x[0], $base); |
| |
| my %z; |
| %z{0} = 10000; |
√ | is(0 + ++%z{0} - 1, $base); |
√ | is(0 + %z{0}-- - 1, $base); |
√ | is(1 * %z{0}, $base); |
√ | is(0 + %z{0}-- - 0, $base); |
√ | is(1 + %z{0}, $base); |
√ | is(1 + %z{0}++, $base); |
√ | is(0 + %z{0}, $base); |
√ | is(0 + ++%z{0} - 1, $base); |
√ | is(0 + --%z{0} + 0, $base); |
√ | is(%z{0}, $base); |
| |
| # Increment of a Str |
From t/operators/auto.t lines 9–98 (38 √, 5 ×): (skip)
| #L<S03/Autoincrement precedence> |
| |
| my $base = 10000; |
| |
| my $x = 10000; |
√ | is(0 + ++$x - 1, $base); |
√ | is(0 + $x-- - 1, $base); |
√ | is(1 * $x, $base); |
√ | is(0 + $x-- - 0, $base); |
√ | is(1 + $x, $base); |
√ | is(1 + $x++, $base); |
√ | is(0 + $x, $base); |
√ | is(0 + --$x + 1, $base); |
√ | is(0 + ++$x + 0, $base); |
√ | is($x, $base); |
| |
| my @x; |
| @x[0] = 10000; |
√ | is(0 + ++@x[0] - 1, $base); |
√ | is(0 + @x[0]-- - 1, $base); |
√ | is(1 * @x[0], $base); |
√ | is(0 + @x[0]-- - 0, $base); |
| |
√ | is(1 + @x[0], $base); |
√ | is(1 + @x[0]++, $base); |
√ | is(0 + @x[0], $base); |
√ | is(0 + ++@x[0] - 1, $base); |
| |
√ | is(0 + --@x[0] + 0, $base); |
√ | is(@x[0], $base); |
| |
| my %z; |
| %z{0} = 10000; |
√ | ok(0 + ++%z{0} - 1 == 10000); |
√ | ok(0 + %z{0}-- - 1 == 10000); |
√ | ok(1 * %z{0} == 10000); |
√ | ok(0 + %z{0}-- - 0 == 10000); |
√ | ok(1 + %z{0} == 10000); |
√ | ok(1 + %z{0}++ == 10000); |
√ | ok(0 + %z{0} == 10000); |
√ | ok(0 + --%z{0} + 1 == 10000); |
√ | ok(0 + ++%z{0} + 0 == 10000); |
√ | ok(%z{0} == 10000); |
| |
| # test magical autoincrement |
| |
| my $foo; |
| |
| $foo = '99'; |
√ | is(++$foo, '100'); |
| |
| $foo = 'a0'; |
√ | is(++$foo, 'a1'); |
| |
| $foo = 'Az'; |
√ | is(++$foo, 'Ba'); |
| |
| $foo = 'zz'; |
√ | is(++$foo, 'aaa'); |
| |
| $foo = 'A99'; |
√ | is(++$foo, 'B00'); |
| |
| # EBCDIC guards: i and j, r and s, are not contiguous. |
| $foo = 'zi'; |
√ | is(++$foo, 'zj'); |
| |
| $foo = 'zr'; |
√ | is(++$foo, 'zs'); |
| |
| # test magical autodecrement |
| |
| $foo = '100'; |
√ | is(--$foo, '99'); |
| |
| $foo = 'a1'; |
× | is(--$foo, 'a0'); |
| |
| $foo = 'Ba'; |
× | is(--$foo, 'Az'); |
| |
| $foo = 'aaa'; |
× | is(--$foo, 'zz'); |
| |
| $foo = 'B00'; |
× | is(--$foo, 'A99'); |
| |
| $foo = 'A00'; |
× | dies_ok( { --$foo }, 'autodecrementing A00 fails' ); |
| |
From t/operators/inc.t lines 7–142 (39 √, 0 ×): (skip)
| #L<S03/Autoincrement precedence> |
| |
| =kwid |
| |
| Mostly copied from Perl 5.8.4 s t/op/inc.t |
| |
| Verify that addition/subtraction properly upgrade to doubles. |
| These tests are only significant on machines with 32 bit longs, |
| and two s complement negation, but should not fail anywhere. |
| |
| =cut |
| |
| my $a = 2147483647; |
| my $c=$a++; |
√ | is($a, 2147483648, "var incremented after post-autoincrement"); |
√ | is($c, 2147483647, "during post-autoincrement return value is not yet incremented"); |
| |
| $a = 2147483647; |
| $c=++$a; |
√ | is($a, 2147483648, "var incremented after pre-autoincrement"); |
√ | is($c, 2147483648, "during pre-autoincrement return value is incremented"); |
| |
| $a = 2147483647; |
| $a=$a+1; |
√ | is($a, 2147483648, 'simple assignment: $a = $a+1'); |
| |
| $a = -2147483648; |
| $c=$a--; |
√ | is($a, -2147483649, "var decremented after post-autodecrement"); |
√ | is($c, -2147483648, "during post-autodecrement return value is not yet decremented"); |
| |
| $a = -2147483648; |
| $c=--$a; |
√ | is($a, -2147483649, "var decremented after pre-autodecrement"); |
√ | is($c, -2147483649, "during pre-autodecrement return value is decremented"); |
| |
| $a = -2147483648; |
| $a=$a-1; |
√ | is($a, -2147483649, 'simple assignment: $a = $a-1'); |
| |
| $a = 2147483648; |
| $a = -$a; |
| $c=$a--; |
√ | is($a, -2147483649, "post-decrement negative value"); |
| |
| $a = 2147483648; |
| $a = -$a; |
| $c=--$a; |
√ | is($a, -2147483649, "pre-decrement negative value"); |
| |
| $a = 2147483648; |
| $a = -$a; |
| $a=$a-1; |
√ | is($a, -2147483649, 'assign $a = -$a; $a = $a-1'); |
| |
| $a = 2147483648; |
| my $b = -$a; |
| $c=$b--; |
√ | is($b, ((-$a)-1), "commpare -- to -1 op with same origin var"); |
√ | is($a, 2147483648, "make sure origin var remains unchanged"); |
| |
| $a = 2147483648; |
| $b = -$a; |
| $c=--$b; |
√ | is($b, ((-$a)-1), "same thing with predecremenet"); |
| |
| $a = 2147483648; |
| $b = -$a; |
| $b= $b - 1; |
√ | is($b, -(++$a), 'est oder of predecrement in -(++$a)'); |
| |
| $a = undef; |
√ | is($a++, 0, 'undef++ == 0'); |
| |
| $a = undef; |
√ | is($a--, undef, 'undef-- is undefined'); |
| |
| $a = 'x'; |
√ | is($a++, 'x', 'magical ++ should not be numified'); |
√ | isa_ok($a, "Str", "it isa Str"); |
| |
| my %a = ('a' => 1); |
| %a{"a"}++; |
√ | is(%a{'a'}, 2, "hash key"); |
| |
| |
| my %b = ('b' => 1); |
| my $var = 'b'; |
| %b{$var}++; |
√ | is(%b{$var}, 2, "hash key via var"); |
| |
| my @a = (1); |
| @a[0]++; |
√ | is(@a[0], 2, "array elem"); |
| |
| my @b = (1); |
| my $moo = 0; |
| @b[$moo]++; |
√ | is(@b[$moo], 2, "array elem via var"); |
√ | is($moo, 0, "var was not touched"); |
| |
| # Test that the expression to increment will only be evaluated once. |
| { |
| my $was_in_foo; |
| my sub foo () { $was_in_foo++; 0 }; |
| |
| my @array = (42); |
| |
√ | is(++@array[+foo()], 43, "++ evaluates the expression to increment only once (1)"); |
√ | is($was_in_foo, 1, "++ evaluates the expression to increment only once (2)"); |
| } |
| |
| # Test case courtesy of Limbic_Region |
| |
| { |
| my $curr = 4; |
| my @array = 1..5; |
√ | is @array[$curr], 5, "postincrements in array subscripts work"; |
| @array[ --$curr ]++; |
| |
√ | is $curr, 3, "postincrements in array subscripts work"; |
√ | is @array[$curr], 5, "postincrements in array subscripts work"; |
| } |
| |
| # test incrementing literals |
| |
| { |
√ | dies_ok { 4++ }, "can't postincrement a literal number"; |
√ | dies_ok { ++4 }, "can't preincrement a literal number"; |
√ | dies_ok { 4-- }, "can't postdecrement a literal number"; |
√ | dies_ok { --4 }, "can't predecrement a literal number"; |
√ | dies_ok { "x"++ }, "can't postincrement a literal string"; |
√ | dies_ok { ++"x" }, "can't preincrement a literal string"; |
√ | dies_ok { "x"-- }, "can't postdecrement a literal string"; |
√ | dies_ok { --"x" }, "can't predecrement a literal string"; |
| } |
As in C, these operators increment or decrement the object in question either before or after the value is taken from the object, depending on whether it is put before or after. Also as in C, multiple references to a single mutating object in the same expression may result in undefined behavior unless some explicit sequencing operator is interposed. See "Sequence points".
As with all postfix operators in Perl 6, no space is allowed between a term and its postfix. See S02 for why, and for how to work around the restriction with an "unspace".
As mutating methods, all these operators dispatch to the type of the operand and return a result of the same type, but they are legal on value types only if the (immutable) value is stored in a mutable container. However, a bare undefined value (in a suitable Scalar container) is allowed to mutate itself into an Int in order to support the common idiom:
say $x unless %seen{$x}++;
Increment of a Str (in a suitable container) works similarly to Perl 5, but is generalized slightly. A scan is made for the final alphanumeric sequence in the string that is not preceded by a '.' character. Unlike in Perl 5, this alphanumeric sequence need not be anchored to the beginning of the string, nor does it need to begin with an alphabetic character; the final sequence in the string matching <!after '.'> <rangechar>+ is incremented regardless of what comes before it.
From t/spec/S03-operators/autoincrement.t lines 52–111 (8 √, 4 ×): (skip)
| #L<S03/Autoincrement precedence/Increment of a> |
| |
| # XXX: these need to be re-examined and extended per changes to S03. |
| # Also, see the thread at |
| # http://www.nntp.perl.org/group/perl.perl6.compiler/2007/06/msg1598.html |
| # which prompted many of the changes to Str autoincrement/autodecrement. |
| |
| my $foo; |
| |
| $foo = '99'; |
√ | is(++$foo, '100'); |
| |
| $foo = 'a0'; |
√ | is(++$foo, 'a1'); |
| |
| $foo = 'Az'; |
√ | is(++$foo, 'Ba'); |
| |
| $foo = 'zz'; |
√ | is(++$foo, 'aaa'); |
| |
| $foo = 'A99'; |
√ | is(++$foo, 'B00'); |
| |
| # EBCDIC guards: i and j, r and s, are not contiguous. |
| $foo = 'zi'; |
√ | is(++$foo, 'zj'); |
| |
| $foo = 'zr'; |
√ | is(++$foo, 'zs'); |
| |
| # test magical autodecrement |
| $foo = '100'; |
√ | is(--$foo, '099'); |
| |
| $foo = 'a1'; |
× | is(--$foo, 'a0'); |
| |
| $foo = 'Ba'; |
× | is(--$foo, 'Az'); |
| |
| $foo = 'aaa'; |
× | is(--$foo, 'aaa'); |
| |
| $foo = 'B00'; |
× | is(--$foo, 'A99'); |
| |
| $foo = 'A00'; |
| is(--$foo, 'A00'); |
| |
| |
| |
| my$file = "/tmp/pix000.jpg"; |
| $file++; # /tmp/pix001.jpg, not /tmp/pix000.jph |
| is($file,'/tmp/pix001.jpg'); |
| |
| my $num = "123.456"; |
| $num++; # 124.456, not 123.457 |
| |
| is($num,'124.456'); |
The <rangechar> character class is defined as that subset of \w that Perl knows how to increment within a range, as defined below.
The additional matching behaviors provide two useful benefits: for its typical use of incrementing a filename, you don't have to worry about the path name or the extension:
$file = "/tmp/pix000.jpg";
$file++; # /tmp/pix001.jpg, not /tmp/pix000.jph
Perhaps more to the point, if you happen to increment a string that ends with a decimal number, it's likely to do the right thing:
$num = "123.456";
$num++; # 124.456, not 123.457
Character positions are incremented within their natural range for any Unicode range that is deemed to represent the digits 0..9 or that is deemed to be a complete cyclical alphabet for (one case of) a (Unicode) script. Only scripts that represent their alphabet in codepoints that form a cycle independent of other alphabets may be so used. (This specification defers to the users of such a script for determining the proper cycle of letters.) We arbitrarily define the ASCII alphabet not to intersect with other scripts that make use of characters in that range, but alphabets that intersperse ASCII letters are not allowed.
If the current character in a string position is the final character in such a range, it wraps to the first character of the range and sends a "carry" to the position left of it, and that position is then incremented in its own range. If and only if the leftmost position is exhausted in its range, an additional character of the same range is inserted to hold the carry in the same fashion as Perl 5, so incrementing '(zz99)' turns into '(aaa00)' and incrementing '(99zz)' turns into '(100aa)'.
The following Unicode ranges are some of the possible rangechar ranges. For alphabets we might have ranges like:
A..Z # ASCII uc
a..z # ASCII lc
Α..Ω # Greek uc
α..ω # Greek lc (presumably skipping U+03C2, final sigma)
א..ת # Hebrew
etc. # (XXX out of my depth here)
For digits we have ranges like:
0..9 # ASCII
٠..٩ # Arabic-Indic
०..९ # Devangari
০..৯ # Bengali
੦..੯ # Gurmukhi
૦..૯ # Gujarati
୦..୯ # Oriya
etc.
Other non-script 0..9 ranges may also be incremented, such as
⁰..⁹ # superscripts (note, cycle includes latin-1 chars)
₀..₉ # subscripts
0..9 # fullwith digits
Conjecturally, any common sequence may be treated as a cycle even if it does not represent 0..9:
Ⅰ..Ⅻ # clock roman numerals uc
ⅰ..ⅻ # clock roman numerals lc
①..⑳ # circled digits 1..20
⒜..⒵ # parenthesize lc
⚀..⚅ # die faces 1..6
❶..❿ # dingbat negative circled 1..10
etc.
While it doesn't really make sense to "carry" such numbers when they reach the end of their cycle, treating such values as incrementable may be convenient for writing outlines and similar numbered bullet items. (Note that we can't just increment unrecognized characters, because we have to locate the string's final sequence of rangechars before knowing which portion of the string to increment. Note also that all character increments can be handled by lookup in a single table of successors since we've defined our ranges not to include overlapping cycles.)
Perl 6 also supports Str decrement with similar semantics, simply by running the cycles the other direction. However, leftmost characters are never removed, and the decrement fails when you reach a string like "aaa" or "000".
Increment and decrement on non-<Str> types are defined in terms of the .succ and .pred methods on the type of object in the Scalar container. More specifically,
++$var
--$var
are equivalent to
$var.=succ
$var.=pred
If the type does not support these methods, the corresponding increment or decrement operation will fail. (The optimizer is allowed to assume that the ordinary increment and decrement operations on integers will not be overridden.)
Increment of a Bool (in a suitable container) turns it true. Decrement turns it false regardless of how many times it was previously incremented. This is useful if your %seen array is actually a KeySet, in which case decrement actually deletes it from the KeySet.
prefix:<++> or postfix:<++> operator
$x++
++$x;
prefix:<--> or postfix:<--> operator
$x--
--$x
infix:<**> exponentiation operator
$x ** 2
If the right argument is not a non-negative integer, the result is likely to be an approximation. If the right argument is of an integer type, exponentiation is at least as accurate as repeated multiplication on the left side's type. (From which it can be deduced that Int**UInt is always exact, since Int supports arbitrary precision.) If the right argument is an integer represented in a non-integer type, the accuracy is left to implementation provided by that type; there is no requirement to recognize an integer to give it special treatment.
prefix:<?>, boolean context
?$x
Evaluates the expression as a boolean and returns True if expression is true or False otherwise. See "true" below for a low-precedence alternative.
prefix:<!>, boolean negation
!$x
Returns the opposite of what ? would. See "not" below for a low-precedence alternative.
prefix:<+>, numeric context
+$x
Unlike in Perl 5, where + is a no-op, this operator coerces to numeric context in Perl 6. (It coerces only the value, not the original variable.) For values that are not already considered numeric, the narrowest appropriate type of Int, Num, or Complex will be returned; however, string containing two integers separated by a / will be returned as a Rat. Exponential notation and radix notations are recognized.
prefix:<->, numeric negation
-$x
Coerces to numeric and returns the arithmetic negation of the resulting number.
prefix:<~>, string context
~$x
Coerces the value to a string. (It only coerces the value, not the original variable.)
prefix:<|>, flatten object into arglist
| $capture
Interpolates the contents of the Capture (or Capture-like) value into the current argument list as if they had been specified literally.
prefix:<+^>, numeric bitwise negation
+^$x
Coerces to integer and then does bitwise negation (complement) on the number.
prefix:<~^>, string bitwise negation
~^$x Coerces to string buffer and then does bitwise negation (complement) on each element.
prefix:<?^>, boolean bitwise negation
?^$x
Coerces to boolean and then flips the bit. (Same as !.)
prefix:<\>, Capture constructor
\$x
\@x
\%x
\($invocant: $pos1, $pos2, :named($arg))
Defers the contextualization of its argument or arguments till it is bound into some other context.
prefix:<^>, upto operator
^$limit
Constructs a range of 0..^$limit or locates a metaclass as a shortcut for $limit.HOW. See "Range semantics".
prefix:<=>, iterate iterator
=$iterator
Unary = reads lines from a filehandle or filename, or iterates an iterator, or in general causes a scalar to explode its guts when it would otherwise not. How it does that is context sensitive. For instance, =$iterator is item/list context sensitive and will produce one value in item context but many values in list context. The production of values is abstract here, so a lazy list merely remembers that it should iterate the iterator to completion upon demand. Use an eager list to force completion.
Use @$iterator to produce a list of all the values even in item context, and $$iterator to produce a single value even in list context. On the other hand, =$capture produces all parts of the capture that makes sense in the current list context, depending on what controls that list context. [Conjecture: the previous sentence is non-sensical.]
infix:<*>
$x*$y
Multiplication, resulting in wider type of the two.
infix:</>
$numerator / $denominator
If either operand is of Num type, converts both operands to Num and does division returning Num. If the denominator is zero, returns an object representing either +Inf, NaN, or -Inf as the numerator is positive, zero, or negative. (This is construed as the best default in light of the operator's possible use within hyperoperators and junctions. Note however that these are not actually the native IEEE non-numbers; they are undefined values of the "unthrown exception" type that happen to represent the corresponding IEEE concepts, and if you subsequently try to use one of these values in a non-parallel computation, it will likely throw an exception at that point.)
If both operands are of integer type, you still get a Num, but the Num type is allowed to do the division lazily; internally it may store a Rat until the time a value is called for. If converted to Rat directly no division ever need be done.
infix:<div>, generic division
$numerator div $denominator
Dispatches to the infix:<div> multi most appropriate to the operand types. Policy on what to do about division by zero is up to the type, but for the sake of hyperoperators and junctions those types that can represent overflow (or that can contain an unthrown exception) should try to do so rather than simply throwing an exception. (And in general, other operators that might fail should also consider their use in hyperops and junctions, and whether they can profitably benefit from a lazy exception model.)
Use of div on two Int values results in a ratio of the Rat type.
infix:<%>, modulus
$x % $mod
Always floor semantics using Num or Int.
infix:<mod>, generic modulus
$x mod $mod
Dispatches to the infix:<mod> multi most appropriate to the operand types.
infix:{'+&'}, numeric bitwise and
$x +& $y
Converts both arguments to integer and does a bitwise numeric AND.
infix:{'+<'}, numeric shift left
$integer +< $bits
infix:{'+>'}, numeric shift right
$integer +> $bits
By default, signed types do sign extension, while unsigned types do not, but this may be enabled or disabled with a :signed or :!signed adverb.
infix:<~&>, buffer bitwise and
$x ~& $y
infix:{'~<'}, buffer bitwise shift left
$buf ~< $bits
infix:{'~>'}, buffer bitwise shift right
$buf ~> $bits
Sign extension is not done by default but may be enabled with a :signed adverb.
infix:<?&>, boolean bitwise and
$x ?& $y
Any bit shift operator may be turned into a rotate operator with the :rotate adverb. If :rotate is specified, the concept of sign extension is meaningless, and you may not specify a :signed adverb.
infix:<+>, numeric addition
$x + $y
Microeditorial: As with most of these operators, any coercion or type mismatch is actually handled by multiple dispatch. The intent is that all such variants preserve the notion of numeric addition to produce a numeric result, presumably stored in suitably "large" numeric type to hold the result. Do not overload the + operator for other purposes, such as concatenation. (And please do not overload the bitshift operators to do I/O.) In general we feel it is much better for you to make up a different operator than overload an existing operator for "off topic" uses. All of Unicode is available for this purpose.
infix:<->, numeric subtraction
$x - $y
infix:<+|>, numeric bitwise inclusive or
$x +| $y
infix:<+^> numeric bitwise exclusive or
$x +^ $y
infix:<~|>, buffer bitwise inclusive or
$x ~| $y
infix:<~^> buffer bitwise exclusive or
$x ~^ $y
infix:<?|>, boolean bitwise inclusive or
$x ?| $y
infix:<?^> boolean bitwise exclusive or
$x ?^ $y
infix:<x>, string/buffer replication
$string x $count
Evaluates the left argument in string context, replicates the resulting string value the number of times specified by the right argument and returns the result as a single concatenated string regardless of context.
If the count is less than 1, returns the null string. The count may not be * because Perl 6 does not support infinite strings. (At least, not yet...) Note, however, that an infinite string may be emulated with cat($string xx *).
infix:<xx>, list replication
@list xx $count
Evaluates the left argument in list context, replicates the resulting Capture value the number of times specified by the right argument and returns the result in a context dependent fashion. If the operator is being evaluated in ordinary list context, the operator returns a flattened list. In slice (@@) context, the operator converts each Capture to a separate sublist and returns the list of those sublists.
If the count is less than 1, returns the empty list, (). If the count is *, returns an infinite list (lazily, since lists are lazy by default).
From t/operators/operator.t lines 17–19 (1 √, 0 ×): (skip)
| # L<S03/Concatenation> |
√ | is($str3, $str4, "~"); |
| |
From t/operators/operator.t lines 49–53 (1 √, 0 ×): (skip)
| # L<S03/Concatenation> |
√ | is("text " ~ "stitching", "text stitching", 'concatenation with ~ operator'); |
| |
| # Bit Stitching |
| |
Functions of one argument
int
sleep
abs
sin
... # see S29 Functions
Note that, unlike in Perl 5, you must use the .meth forms to default to $_ in Perl 6.
There is no unary rand function in Perl 6, though there is a .rand method call and a 0-ary rand term.
prefix:<int>
Coerces to type Int. Floor semantics are used for fractional values, including strings that appear to express fractional values. That is, int($x) must have the same result as int(+$x) in all cases. All implicit conversions to integer use the same semantics.
(Note that, despite the fact that int is a valid native type name, this function does not express conversion to that native type. Such subtype conversions are done automatically upon assignment to a subtyped container, and fail if the container cannot hold the value.)
prefix:<sleep>
Suspends the current thread of execution for the specified number of seconds, which may be fractional.
prefix:<abs>
Returns the absolute value of the specified argument.
infix:<but>
$value but Mixin
infix:<does>
$object does Mixin
$num1 <=> $num2
$str1 leg $str2
$obj1 cmp $obj2
These operators compare their operands using numeric, string, or eqv semantics respectively, and depending on the order return one of Order::Increase, Order::Same, or Order::Decrease (which numerify to -1, 0, or +1). See "Comparison semantics".
$min .. $max
$min ^.. $max
$min ..^ $max
$min ^..^ $max
Constructs Range objects, optionally excluding one or both endpoints. See "Range semantics".
From t/spec/S03-operators/equality.t lines 10–41 (15 √, 0 ×): (skip)
| #L<S03/Chaining binary precedence> |
| #L<S03/Comparison semantics> |
| |
| # string equality & inequality |
√ | ok("a" eq "a", "eq true"); |
√ | ok(!("a" eq "ab"), "eq false"); |
√ | ok("a" ne "ab", "ne true"); |
√ | ok(!("a" ne "a"), "ne false"); |
| |
| # potential problem cases |
√ | ok("\0" eq "\0", "eq on strings with null chars"); |
| |
| # string context on undef values |
| my $foo; |
√ | ok($foo eq "", "Undef eq ''"); |
√ | ok($foo ne "f", "Undef ne 'f'"); |
| |
| my @foo; |
√ | ok(@foo[0] eq "", "Array undef eq ''"); |
√ | ok(@foo[0] ne "f", "Array undef ne 'f'"); |
| |
| # numeric equality & inequality |
√ | ok(2 == 2, "== true"); |
√ | ok(!(2 == 3), "== false"); |
√ | ok(2 != 3, "!= true"); |
√ | ok(!(2 != 2), "!= false"); |
| |
| # numeric context on undef values |
√ | ok($foo == 0, "Undef == 0"); |
√ | ok(@foo[0] == 0, "Array undef == 0"); |
| |
| # XXX: need tests for coercion string and numeric coercions |
From t/spec/S03-operators/relational.t lines 9–49 (20 √, 0 ×): (skip)
| #L<S03/Chaining binary precedence> |
| |
| # from t/operators/relational.t |
| |
| ## numeric relationals ( < , >, <=, >= ) |
| |
√ | ok(1 < 2, '1 is less than 2'); |
√ | ok(!(2 < 1), '2 is ~not~ less than 1'); |
| |
√ | ok(2 > 1, '2 is greater than 1'); |
√ | ok(!(1 > 2), '1 is ~not~ greater than 2'); |
| |
√ | ok(1 <= 2, '1 is less than or equal to 2'); |
√ | ok(1 <= 1, '1 is less than or equal to 1'); |
√ | ok(!(1 <= 0), '1 is ~not~ less than or equal to 0'); |
| |
√ | ok(2 >= 1, '2 is greater than or equal to 1'); |
√ | ok(2 >= 2, '2 is greater than or equal to 2'); |
√ | ok(!(2 >= 3), '2 is ~not~ greater than or equal to 3'); |
| |
| ## XXX: need tests for numeric coercion |
| |
| ## string relationals ( lt, gt, le, ge ) |
| |
√ | ok('a' lt 'b', 'a is less than b'); |
√ | ok(!('b' lt 'a'), 'b is ~not~ less than a'); |
| |
√ | ok('b' gt 'a', 'b is greater than a'); |
√ | ok(!('a' gt 'b'), 'a is ~not~ greater than b'); |
| |
√ | ok('a' le 'b', 'a is less than or equal to b'); |
√ | ok('a' le 'a', 'a is less than or equal to a'); |
√ | ok(!('b' le 'a'), 'b is ~not~ less than or equal to a'); |
| |
√ | ok('b' ge 'a', 'b is greater than or equal to a'); |
√ | ok('b' ge 'b', 'b is greater than or equal to b'); |
√ | ok(!('b' ge 'c'), 'b is ~not~ greater than or equal to c'); |
| |
| ## XXX: need tests for string coercion |
| |
| ## Multiway comparisons (RFC 025) |
All operators on this precedence level may be chained; see "Chained comparisons".
infix:<==> etc.
From t/operators/operator.t lines 26–48 (13 √, 0 ×): (skip)
| # L<S03/Chaining binary precedence/==> |
| my $five = 5; |
| my $four = 4; |
| my $wibble = 4; |
| |
√ | ok(!($five == $four), "== (false)"); |
√ | ok($wibble == $four, "== (true)"); |
√ | ok(!($wibble != $four), "== (false)"); |
√ | ok($five != $four, "!= (true)"); |
| |
√ | ok($five == 5, "== (const on rhs)"); |
√ | ok(!($five != 5), "!= (const on rhs)"); |
| |
√ | ok(5 == $five, "== (const on lhs)"); |
√ | ok(!(5 != $five), "!= (const on lhs)"); |
| |
√ | ok($five == (2 + 3), "== (sum on rhs)"); |
√ | ok(!($five != (2 + 3)), "== (sum on rhs)"); |
| |
√ | is(2 + 3, $five, "== (sum on lhs)"); |
√ | ok((2 + 3) == 5, "== (sum on lhs)"); |
√ | ok(!((2 + 3) != $five), "== (sum on lhs)"); |
| |
== != < <= > >=
As in Perl 5, converts to Num before comparison. != is short for !==.
infix:<eq> etc.
eq ne lt le gt ge
As in Perl 5, converts to Str before comparison. ne is short for !eq.
$a before $b
$a after $b
$obj ~~ $pattern
Perl 5's =~ becomes the "smart match" operator ~~, with an extended set of semantics. See "Smart matching" for details.
To catch "brainos", the Perl 6 parser defines an infix:<=~> operator which always fails at compile time with a message directing the user to use ~~ or ~= (string append) instead if they meant it as a single operator, or to put a space between if they really wanted to assign a stringified value as two separate operators.
From t/operators/brainos.t lines 15–24 (no results): (skip)
| #L<S03/Chaining binary precedence/"To catch"> |
| |
| my $str = 'foo'; |
| eval q{$str =~ m/bar/;}; |
| if $!.defined { |
| pass "caught =~ braino, saying $!"; |
| } |
| else { |
| flunk "didn't catch =~ braino"; |
| } |
A negated smart match is spelled !~~.
From t/operators/negated_smartmatch.t lines 7–10 (1 √, 0 ×): (skip)
| #L<S03/Chaining binary precedence/"A negated smart match is spelled"> |
| |
| my $opposites = (not(0 ~~ rx:Perl5/0/) xor not(0 !~~ rx:Perl5/0/)); |
√ | ok($opposites, "~~ and !~~ are opposites"); |
VAR($a) =:= VAR($b)
From t/operators/value_equivalence.t lines 7–131 (39 √, 3 ×): (skip)
| L<S03/"Chaining binary precedence" /Value identity> |
| |
| C<===> and C<eqv> are 2 distinct operators, where C<===> tests value |
| equivalence for immutable types and reference equivalence for |
| mutable types, and C<eqv> tests value equivalence for snapshots of mutable |
| types. So C<(1,2) === (1,2)> returns true but C<[1,2] === [1,2]> returns |
| false, and C<[1,2] eqv [1,2]> returns true. |
| |
| =cut |
| |
| <