Operators provide a simple syntax for manipulating values. Many of the Perl 6 operators will be familiar, especially to Perl programmers.
The =
operator is for ordinary assignment.
It creates a copy of the values on the right-hand side and assigns
them to the variables or data structures on the left-hand side:
$copy = $original; @copies = @originals;
$copy
and $original
both have
the same value, and @copies
has a copy of every
element in @originals
.
The :=
operator is for binding assignment.
Instead of copying the value from one variable or structure to the
other, it creates an alias. An alias is an additional entry in the
symbol table with a different name for the one container:
$a := $b; # $a and $b are aliases @c := @d; # @c and @d are aliases
In this example, any change to $a
also changes
$b
, because they’re just two
separate names for the same container. Binding assignment requires
the same number of elements on both sides, so both of these would be
an error:
# ($a, $b) := ($c); # error # ($a, $b) := ($c, $d, $e); # error
The ::=
operator is a variant of the binding
operator that binds at compile time.
The binary arithmetic operators are
addition (+
),
subtraction (-
),
multiplication
(*
),
division (/
),
modulus (%
), and
exponentiation
(**
). Each has a corresponding
assignment operator
(+=
,
-=
, *=
, /=
,
%=
, **=
) that combines the
arithmetic operation with assignment:
$a = 3 + 5; $a += 5; # $a = $a + 5
The unary arithmetic operators are the
prefix and postfix autoincrement (++
) and
autodecrement (--
) operators. The prefix operators
modify their argument before it’s evaluated, and the
postfix operators modify it afterward:
$a++; $a--; ++$a; --$a;
The
~
operator concatenates strings. The
corresponding ~=
operator concatenates the right-hand
side of the assignment to the end of the string:
$line = "The quick brown " ~ $fox ~ jumps_over( ) ~ " the lazy " ~ $dog; $line ~= "Belgium"; # adds to the string
The x
operator replicates strings. It always
returns a string no matter whether the left side of the operation is
a single element or a list. The following example assigns the string
“LintillaLintillaLintilla”:
$triplet = "Lintilla" x 3;
The corresponding x=
operator replicates the
original string and assigns it back to the original variable:
$twin = "Lintilla"; $twin x= 2; # "LintillaLintilla"
The xx
operator replicates lists. It returns a
list no matter whether it operates on a list of elements or a single
element. The following example assigns a list of three elements to
@array
, each with the value
“Lintilla”:
@array = "Lintilla" xx 3;
The corresponding xx=
operator creates a list that
contains the specified number of copies of every element in the
original array and assigns it back to the array variable:
@array xx= 2; # twice as many elements @array = (@array, @array); # equivalent
Each comparison operator has two forms, one for numeric comparisons
and one for string comparisons. The comparison operators are
greater-than
(>
, gt
), less-than
(<
, lt
),
greater-than-or-equal (>=
,
ge
), less-than-or-equal (<=
,
le
), equality (= =
,
eq
), and inequality (!=
,
ne
). Each returns a true value if the relation is
true and a false value otherwise. The generic
comparison operator
(<=>
, cmp
) returns
0
if the two arguments are equal,
1
if the first is greater, and
-1
if the second is greater.
The binary logical operators test two values and return one value or the other depending on certain truth conditions. They’re also known as the short-circuit operators because the right-hand side will never be evaluated if the overall truth value can be determined from the left-hand side. This makes them useful for conditionally assigning values or executing code.
The AND
relation has the &&
operator and the
low-precedence and
operator. If the left-hand side
is false, its value is returned. If the left-hand value is true, the
right-hand side is evaluated and its value is returned:
$splat = $whale && $petunia; $splat = ($whale and $petunia);
The OR relation
has the ||
operator and the low-precedence
or
operator. The left-hand value is returned if it
is true, otherwise the right-hand value is evaluated and returned:
$splat = $whale || $petunia; $splat = ($whale or $petunia);
A variant of the OR relation tests for definedness instead of truth.
It uses the //
operator and the low-precedence
err
operator. The left-hand value is returned if
it is defined, otherwise the right-hand side is evaluated and its
value returned:
$splat = $whale // $petunia; $splat = ($whale err $petunia);
The XOR
relation has the ^^
operator and the
low-precedence xor
operator. It returns the value
of the true operand if any one operand is true and a false value if
both are true or neither is true. xor
isn’t short-circuiting like the others, because it
always has to evaluate both arguments to know if the relation is
true:
$splat = $whale ^^ $petunia; $splat = ($whale xor $petunia);
Perl 6 also has boolean variants of the logical
operators: ?&
(AND),
?|
(OR), and
?^
(XOR). These always return a true or
false value.
The context of an expression specifies the type of value it is expected to produce. An array expects to be assigned multiple values at the same time, so assignment to an array happens in “list” context. A scalar variable expects to be assigned a single value, so assignment to a scalar happens in “scalar” context. Perl expressions often adapt to their context, producing values that fit with what’s expected.
Contexts have proven to be valuable tools in Perl 5, so Perl 6 has a few more added. Void context still exists. Scalar context is subdivided into boolean, integer, numeric, string, and object contexts. Aside from flattening list context and hashlist context, which we mentioned earlier, list context is further subdivided into non-flattening list context and lazy list context.
- Void context
Expects no value.
- Scalar context
Expects a single value. Composite values are automatically referenced in scalar context.
- Boolean context
Expects a true or false value. This includes the traditional definitions of truth—where
0
,undef
, and the empty string are false and all other values are true—and values flagged with the propertiestrue
orfalse
.- Numeric context
Expects a number, whether it’s an integer or floating-point, and whether it’s decimal, binary, octal, hex, or some other base.
- Integer context
Expects an integer value. Strings are treated as numeric and floating- point numbers are truncated.
- String context
Expects a string value. It interprets any information passed to it as a string of characters.
- Object context
Expects an object, or more specifically, a reference to an object.
- List context
Expects a collection of values. Any single value in list context is treated as a one-element list.
- Non-flattening list context
Expects a list of objects. It treats arrays, hashes, and other composite values as discrete entities.
- Flattening list context
Expects a list, but flattens out arrays and hashes into their component parts.
- Hashlist context
Expects a list of pairs. A simple list in hashlist context pairs up alternating elements.
- Lazy list context
Expects a list, just like non-flattening list context, but doesn’t require all the elements at once.
The unary context operators force a particular context when it wouldn’t otherwise be imposed. Most of the time the default context is the right one, but at times you might want a little more control.
The unary ?
operator and the low-precedence
true
force boolean context. Assignment of a scalar
to a scalar only imposes generic scalar context, so the value of
$number
is simply copied. With the
?
operator, you can force boolean context and
assign the truth value of the variable instead of the numeric value:
$value = $number; $truth = ?$number;
The unary !
operator and the low-precedence
not
also force boolean context, but they negate
the value at the same time. They’re often used in a
boolean context, where only the negating effect is visible:
$untruth = !$number;
The unary +
operator forces numeric context, and
-
forces negative numeric context:
$number = +$string; $negnum = -$string;
The unary ~
operator forces string context:
$string = ~$number;
Perl 6 has two sets of
bitwise
operators, one for integers and one for strings. The
integer bitwise operators are
+&
, +|
, and
+^
. Notice the combination of the AND, OR, and XOR
relation symbols with the general numeric symbol +
(the unary numeric context operator). There are also the numeric
bitwise shift operators
<<
and >>
.
The string bitwise operators are
~&
, ~|
, and
~^
. These combine the AND, OR, and XOR relation
symbols with the general string symbol ~
(the same
symbol as string concatenation and the unary string context
operator).
Each of the bitwise operators has an assignment counterpart
+&=
, +|=
,
+^=
, <<=
,
>>=
, ~&=
,
~|=
, and ~^=
.
The ternary ??:
: operator evaluates either its second
or third operand, depending on whether the first operand evaluates as
true or false. It’s basically an if-then-else
statement acting as an expression:
$form = ($heads = = 2) ?? "Zaphod" :: "ape-descended lifeform";
The vector
operators are designed to work with lists. They’re
simply modified versions of the standard scalar operators. Every
operator has a vectorized version, even user-defined operators. They
have the same basic forms as their scalar counterparts, but are
marked with the bracketing characters » and
«,[8] or their plain-text equivalents
>>
and <<
.
So, the
vectorized addition operator is >>+<<
.
Vector operators impose list context on their operands and distribute
their operations across all the operands’ elements.
Vector addition takes each element from the first list and adds it to
the corresponding element in the second list:
@sums = @first >>+<< @second;
The resulting array contains the sums of each pair of elements, as if each pair were added with the scalar operator:
@sums = ( (@first[0] + @second[0]), (@first[1] + @second[1]), etc...);
If one side of a vector operation is a simple scalar, it is distributed across the list as if it were a list of identical elements:
@sums = @numbers >>+<< 5; @sums ( (@numbers[0] + 5), (@numbers[1] + 5), etc... );
At the simplest level,
junction
operators are no more than AND, OR, XOR, and NOT for values instead
of expressions. The binary junction operators are
&
(AND),
|
(OR), and ^
(XOR).[9]
So while ||
is a logical operation on
two expressions:
if ($value = = 1) || ($value = = 2) { ... }
|
is the same logical relation between two values:
if ($value = = 1 | 2) { ... }
In fact, those two examples have exactly the same result: they return
true when $value
is 1
or
2
and false otherwise. In the common case
that’s all you’ll ever need to
know.
But junctions are a good deal more powerful than that, once you learn their secrets. In scalar context, a junctive operation doesn’t return an ordinary single value, it returns a composite value containing all of its operands. This return value is a junction, and it can be used anywhere a junction operation is used:
$junc = 1 | 2; if ($value = = $junc) { ... }
Here, the variable $junc
is used in place of
1 | 2
, and has exactly the same effect as the
earlier example.
A junction is basically just an unordered set with a logical relation defined between its elements. Any operation on the junction is an operation on the entire set. Table 4-1 shows the way the four different types of junctions interact with other operators.
Table 4-1. Junctions
Function |
Operator |
Relation |
Meaning |
---|---|---|---|
|
|
AND |
Operation must be true for all values. |
|
|
OR |
Operation must be true for at least one value. |
|
|
XOR |
Operation must be true for exactly one value. |
|
NOT |
Operation must be false for all values. |
The simplest possible example is the result of evaluating a junction
in boolean context. The operation on the set is just
“is it true?” This operation on an
all
junction is true if all
the values are true:
true( $a & $b ) true( all($a,$b) )
So, if $a
and $b
are both true,
the result is true.
On an any
junction, it’s true if
any one value is true:
true( $a | $b ) true( any($a,$b) )
So, if $a
or $b
is true or if
both are true, the result is true.
On a one
junction, it’s true only
if exactly one value is true:
true( $a ^ $b ) true( one($a,$b) )
So, if either $a
or $b
is true,
the result is true. But, if $a
and
$b
are both true or neither is true, the result is
false.
On a none
junction, it’s true
only when none of the values are true—that
is, when all the values are false.
true( none($a,$b) )
So, if $a
and $b
are both
false, the result is true.
Ordinary arithmetic operators interact with junctions much like vector operators on arrays. A junction distributes the operation across all of its elements:
$junc = any(1, 2); $junc += 5; # $junc is now any(6, 7)
Junctions can be combined to produce compact and powerful logical comparisons. If you want to test that two sets have no intersection, you might do something like:
if all($a, $b) = = none($c, $d) { ... }
which tests that all of the elements of the first set are equal to none of the elements of the second set. Translated to ordinary logical operators that’s:
if ($a != $c) && ($a != $d) && ($b != $c) && ($b != $d) { ... }
If you want to get back a flat list of values from a junction, use
the .values
method:
$junc = all(1, 2, 3); # create a junction $sums = $junc + 3; # add 3 @set = $sums.values( ); # (4, 5, 6)
The .dump
method returns a string that shows the
structure of a junction:
$string = $sums.dump( ); # "all(4,5,6)"
The .pick
method selects one value from an
any
junction or a one
junction
that has exactly one value, and returns it as an ordinary scalar:
$junc = any(1, 2, 3); $single = $junc.pick( ); # may be 1, 2, or 3
On an all
junction, a none
junction, or a one
junction with more than one
value, .pick
returns
undef
.[10]
The binary ~~
operator makes a smart match between its two terms. It
returns a true value if the match is successful and a false value if
the match fails.[11] The negated smart match operator
!~
does the exact opposite: it returns
true if the match fails and false if it is successful. The kind of
match a smart match does is determined by the kind of arguments it
matches. If the types of the two arguments can’t be
determined at compile time, the kind of match is determined at
runtime. In all but two cases smart match is a symmetric operator, so
you can reverse A ~~ B
to B ~~ A
and it will have the same truth value.
Any
scalar
value or any code that results in a scalar value matched against a
string tests for string equality. The following match is true if
$string
has the value
“Ford”:
$string ~~ "Ford"
Any scalar value matched against a numeric value tests for numeric
equality. The following is true if $number
has the
numeric value 42, or the string value
“42”:
$number ~~ 42
An expression that results in the value 42 is also true:
( (5 * 8) + 2 ) ~~ 42
Any scalar value matched against an undefined value checks for
definedness. The following matches are true if
$value
is an undefined value and false if
$value
is any defined value:
$value ~~ undef $value ~~ $undefined_value
Any scalar value matched against a rule (regex) does a pattern match.
The following match is true if the sequence
“towel” can be found anywhere
within $string
:
$string ~~ /towel/
Any scalar value matched against a substitution does that
substitution on the value. This means the value has to be modifiable.
The following match is true if the substitution succeeds on
$string
and false if it fails:
$string ~~ s/weapon/towel/
Any scalar value matched against a boolean value simply takes the truth value of the boolean. The following match will always be true, because the boolean on the right is always true:[12]
$value ~~ (1 = = 1)
The boolean value on the right must be an actual boolean: the result
of a boolean comparison or operation, the return value of a
not
or true
function, or a
value forced into boolean context by !
or
?
. The boolean value also must be on the right; a
boolean on the left is treated as an ordinary scalar value.
Any scalar value matched against a list compares each element in sequence.
The match is true if at least one the element of the list would match
in a simple expression-to-expression match. The following match is
true if $value
is the same as any of the three
strings on the right:
$value ~~ ( "Zaphod", "Ford", "Trillian" )
This match is short-circuiting. It stops after the first successful
match. It has the same truth value as a series of
or
-ed matches:
($value ~~ "Zaphod") or ($value ~~ "Ford") or ($value ~~ "Trillian")
A list can contain any combination of elements: scalar values, rules, boolean expressions, arrays, hashes, etc.:
$value ~~ ( "Zaphod", 5, /petunias/ )
A match of a list against another list sequentially compares each element in the first list to the corresponding element in the second list. The match is true if every element of the first list matches the corresponding element in the second list. The following match is true, because the two lists are identical:
( "Zaphod", "Ford", "Trillian" ) ~~ ( "Zaphod", "Ford", "Trillian" )
The two lists don’t have to be identical, as long as they’re the same length and their corresponding elements match:
( $zaphod, $ford, $trillian ) ~~ ( "Zaphod", /Ford/, /^T/ )
The list-to-list match is also short-circuiting. It stops after the
first failed match. This has the same truth value as a series of
single-element smart matches linked by and
:
($zaphod ~~ "Zaphod") and ($ford ~~ /Ford/) and ($trillian ~~ /^T/)
A nonnumeric expression matched against an
array
sequentially searches for that value in the array. The match is true
if the value is found. If @array
contains the
values “Zaphod”,
“Ford”, and
“Trillian”, the following match is
true when $value
is the same as any of those three
strings:
$value ~~ @array
An integer value matched against an array tests the truth of the
value at that numeric index. The following match is true if the
element @array[2]
exists and has a true value:
2 ~~ @array
An integer value matched against an array reference also does an index lookup:
2 ~~ [ "Zaphod", "Ford", "Trillian" ]
This match is true, because the third element of the array reference is a true value.
An array matches just like a list of scalar values if
it’s flattened with the *
operator.[13]
So, the following example searches the array for an
element with the value 2
, instead of doing a index
lookup:
2 ~~ *@array
An array matched against a rule does a pattern match across the
array. The match is true if any element of the array matches the
rule. If “Trillian”,
“Gillian”, or
“million” is an element of
@array
, the following match is true, no matter
what the other elements are:
@array = ( "Zaphod", "Ford", "Trillian" ); @array ~~ /illi/
A match of an array against an array sequentially compares each element in the first array to the corresponding element in the second array:
@humans ~~ @vogons
This match is true if the two arrays are the same length and
@humans[0]
matches @vogons[0]
,
@humans[1]
matches @vogons[1]
,
etc.
A hash matched against any scalar value tests the truth value of the hash entry with that key:
$key ~~ %hash
This match is true if the element %hash{$key}
exists and has a true value.
A hash matched against a rule does a pattern match on the hash keys:
%hash ~~ /bl/
This match is true if at least one key in %hash
matches “bl”.
A hash matched against a hash checks for intersection between the keys of the two hashes:
%vogons ~~ %humans
So, this match is true if at least one key from
%vogons
is also a key of
%humans
. If you want to see that two hashes have
exactly the same keys, match their lists of keys:
%vogons.keys ~~ %humans.keys
A hash matched against an array checks a slice of a hash to see if its values are true. The match is true if any element of the array is a key in the hash and the hash value for that key is true:
%hash ~~ @array
If @array
has one element
`blue’ and %hash
has a corresponding key `blue', the
match is true if %hash{'blue'}
has a true value,
but false if %hash{'blue'}
has a false value
(`0', an empty string or undef).
An expression matched against an any
junction
is a recursive disjunction. The match is true if at least one of the
elements of the list would match in a simple expression-to-expression
match:
$value ~~ any("Zaphod", "Ford", "Trillian")
This example matches if $value
is the same as any
of the three strings on the right. The effect of this comparison is
the same as a simple comparison to a list, except that it
isn’t guaranteed to compare in any particular order.
A smart match of an all
junction is only true when
the expression matches every value in the junction:
/illi/ ~~ all("Gillian", "million", "Trillian") # match succeeds /illi/ ~~ all("Zaphod", "Ford", "Trillian") # match fails
A smart match of a one
junction is only true when
the expression matches exactly one value in the junction:
/illi/ ~~ one("Zaphod", "Ford", "Trillian") # match succeeds /illi/ ~~ one("Gillian", "million", "Trillian") # match fails
A smart match of a none
junction is true when it
doesn’t match any values in the junction:
/illi/ ~~ none("Zaphod", "Ford", "Marvin") # match succeeds /illi/ ~~ none("Zaphod", "Ford", "Trillian") # match fails
An any
junction matched against another
any
junction is a recursive disjunction of every
value in the first junction to every value in the second junction.
The match is true if at least one value of the first junction matches
at least one value in the second junction:
any("Ford", "Trillian") ~~ any("Trillian", "Arthur")
This match is true, because “Trillian” is in both junctions.
An
object
matched against a class name is true if the object belongs to that
class, or inherits from that class. It’s essentially
the same as calling the .isa
method on the object:
$ship ~~ Vogon::Constructor # $ship.isa(Vogon::Constructor)
An object calls a method it’s matched against. The match is true if the method returns a true value:
$ship ~~ .engage # $ship.engage
Any expression matched against a subroutine tests the return value of the subroutine. If the subroutine takes no arguments it is treated as a simple boolean:
$value ~~ my_true
If the subroutine has a one argument signature and it is the same variable type as the expression, the subroutine is called with the expression as its argument. The return value of the subroutine determines the truth of the match:
$value ~~ value_test # value_test($value) @array ~~ array_test # array_test(@array) %hash ~~ hash_test # hash_test(%hash)
The unary \
operator returns a reference to its
operand. The referencing operator
isn’t needed very often, since scalar context
automatically generates references to arrays, hashes, and functions,
but it is still needed in flattening contexts and other contexts that
don’t auto-reference:
@array_of_refs = ( \@a, \@b, \@c );
The unary *
operator (that’s the
“splat” operator) flattens a list
in a context where it would usually be taken as a reference. On an
rvalue,
*
causes the array to be treated as a simple list:
@combo = ( \@array, \%hash); @a := @combo; # @a is @combo (@b, %c) := *@combo; # @b is @array, %c is %hash
Since the @combo
array contains an arrayref and a
hashref, an ordinary binding assignment of @combo
to @a
treats @combo
as a single
element and binds it to @a
. With the flattening
operator, the @combo
array is treated as a simple
list, so each of its elements are bound to a separate element on the
left-hand side. @b
is bound to the original
@array
and %c
is bound to the
original %hash
.
On an lvalue, *
tells the array
to “slurp” all available arguments.
An ordinary binding of two arrays to two arrays simply binds the
first element on the right-hand side to the first element on the
left-hand side, and the second to the second:
(@a, @b) := (@c, @d); # @a is @c, @b is @d *@a := (@c, @d); # @a contains @c and @d
So, @a
is bound to @c
, and
@b
is bound to @d
. With the
*
operator, the first element on the left-hand
side sucks up all the elements on the right-hand side, so
@a
contains all the elements from
@c
and @d
.
One common use for *
is in defining subroutine and
method signatures, as you will see in Section 4.4 later in this chapter.
The ¦ operator takes two lists (arrays, hash keys, etc.) and returns a single list with alternating elements from each of the original lists. This allows loops and other iterative structures to iterate through the elements of several lists at the same time:
@a = (1, 2, 3); @b = (4, 5, 6); @c = @a ¦ @b; # @c is (1, 4, 2, 5, 3, 6)
There is no equivalent ASCII operator for the zip operator, but the
zip
function is much more fully featured than the
operator. It is described in Section 4.3.2.3 later in this
chapter.
[8] These are the Unicode RIGHT POINTING GUILLEMET (U+00BB) and LEFT POINTING GUILLEMET (U+00AB) characters.
[9] There isn’t an operator for junctive NOT, but there is a function, as you’ll see shortly.
[10] With some levels of error strictness, it may raise an exception.
[11] This is an oversimplification. Some matches return a more complex value, but in boolean context it will always evaluate as true for a successful match, and false for a failed match.
[12] At the moment this relation won’t seem particularly useful. It makes much more sense when you realize that the switch statement duplicates all the smart match relations. More on that in Section 4.3.1.3 later in this chapter.
[13] See Section 4.2.12 later in the chapter.
Get Perl 6 Essentials now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.