Operators
Visit Modern Perl to download your own copy of this book or
buy Modern Perl at Amazon.
Some people call Perl an "operator-oriented language". A Perl operator is a series of one or more symbols used as part of the syntax of a language. Each operator operates on zero or more operands. Think of an operator as a special sort of function the parser understands and its operands as arguments.
You've seen how Perl manages context through its operators. To understand Perl fully, you must understand how operators interact with their operands.
Operator Characteristics
Every operator possesses several important characteristics which govern its behavior: the number of operands on which it operates, its relationship to other operators, the contexts it enforces, and the syntax it provides.
perldoc perlop and perldoc perlsyn provide voluminous information about Perl's operators, but the docs assume you're already familiar with a few essential computer science concepts. Fortunately, you'll recognize these ideas from written language and elementary mathematics, even if you've never heard their complicated names before.
Precedence
The precedence of an operator governs when Perl should evaluate it in an expression. Perl evaluates the operator with the highest precedence first, then the next highest, all the way to the lowest precedence. Remember basic math? Multiply and divide before you add and subtract. That's precedence. Because the precedence of multiplication is higher than the precedence of addition, in Perl 7 + 7 * 10 evaluates to 77, not 140.
Use grouping parentheses to force the evaluation of some operators before others. In (7 + 7) * 10, grouping the addition into a single unit forces its evaluation before the multiplication—though Perl wants to perform the multiplication first, it has to evaluate the grouped subexpression into a single value as the multiplication operator's left operand. The result is 140.
perldoc perlop contains a table of precedence. Skim it a few times, but don't bother memorizing it (almost no one does). Spend your time simplifying your code where you can. Then add parentheses where they clarify.
In cases where two operators have the same precedence, other factors such as associativity (Associativity) and fixity (Fixity) break the tie.
Associativity
The associativity of an operator governs whether it evaluates from left to right or right to left. Addition is left associative, such that 2 + 3 + 4 evaluates 2 + 3 first, then adds 4 to the result, not that order of evaluation matters. Exponentiation is right associative, such that 2 ** 3 ** 4 evaluates 3 ** 4 first, then raises 2 to the 81st power. Use parentheses if you write code like this.
If you memorize only the precedence and associativity of the common mathematical operators, you'll be fine. Simplify your code and you won't have to memorize other associativities. If you can't simplify your code (or if you're maintaining code and trying to understand it), use the core B::Deparse module to see exactly how Perl handles operator precedence and associativity.
Run perl -MO=Deparse,-p on a snippet of code The -p flag adds extra grouping parentheses which often clarify evaluation order. Beware that Perl's optimizer will simplify mathematical operations using constant values. If you really need to deparse a complex expression, use named variables instead of constant values, as in $x ** $y ** $z.
Arity
The arity of an operator is the number of operands on which it operates. A nullary operator operates on zero operands. A unary operator operates on one operand. A binary operator operates on two operands. A trinary operator operates on three operands. A listary operator operates on a list of zero or more operands.
Arithmetic operators are binary operators and are usually left associative. This has implications for tie-breaking evaluation order of operands with the same precedence. For example, 2 + 3 - 4 evaluates 2 + 3 first. Addition and subtraction have the same precedence, but they're left associative and binary, so the proper evaluation order applies the leftmost operator (+) to the leftmost two operands (2 and 3) with the leftmost operator (+), then applies the rightmost operator (-) to the result of the first operation and the rightmost operand (4).
Fixity
Perl novices often find confusion between the interaction of listary operators—especially function calls—and nested expressions. Where parentheses usually help, beware of the parsing complexity of:
# probably buggy code
say ( 1 + 2 + 3 ) * 4;
... which prints the value 6 and (probably) evaluates as a whole to 4 (the return value of say multiplied by 4). Perl's parser happily interprets the parentheses as postcircumfix operators denoting the arguments to say, not circumfix parentheses grouping an expression to change precedence.
An operator's fixity is its position relative to its operands:
- Infix operators appear between their operands. Most mathematical operators are infix operators, such as the multiplication operator in
$length * $width. - Prefix operators precede their operands. Postfix operators follow their operands. These operators tend to be unary, such as mathematic negation (
-$x), boolean negation (!$y), and postfix increment ($z++). - Circumfix operators surround their operands, as with the anonymous hash constructor (
{ ... }) and quoting operators (qq[ ... ]). - Postcircumfix operators follow certain operands and surround others, as seen in hash and array element access (
$hash{$x}and$array[$y]).
Operator Types
Perl's operators provide value contexts (Numeric, String, and Boolean Context) to their operands. To choose the appropriate operator, you must know the values of the operands you provide as well as the value you expect to receive.
Numeric Operators
Numeric operators impose numeric contexts on their operands. These operators are the standard arithmetic operators of addition (+), subtraction (-), multiplication (*), division (/), exponentiation (**), and modulo (%), their in-place variants (+=, -=, *=, /=, **=, and %=), and both postfix and prefix auto-decrement (--).
The auto-increment operator has special string behavior (