Perl Part I · Module 3 · Operators and Expressions
Precedence and Saying What You Mean
This chapter introduces no new operator. Its job is to hand you the single table that explains every grouping surprise in this module — why minus two squared is negative four, why an open with a double-pipe never reaches its die, why assigning the result of an or-expression stores the wrong value — and then to make the case that you should not rely on remembering it. Four rows account for almost every real defect, and the honest advice for everything else is to write the parentheses. Not because precedence is hard, but because a reader reviewing your diff at the end of a long day should not have to consult a table to know what your line computes.
Foundation14 min readPerlPart IFundamentalsPrecedenceReadabilityOperators
Part I · Module 3 · Chapter 3.12 · Precedence and Saying What You Mean
1. Two Rules, Then the Table
Every surprise in this module came from one of two questions.
Precedence — which operator is applied first when two different operators meet. 2 + 3 * 4 is 14 rather than 20 because * has higher precedence than +.
Associativity — which end to start from when two operators of the same precedence meet. Chapter 3.1 showed 18 / 20 * 100 grouping left to right; Chapter 3.2 showed ** grouping right to left.
That is the entire theory. The rest is a lookup.
2. The Table
This is quoted from perldoc perlop, which is where it lives and where you should go to check it. Highest precedence at the top; the left column is the associativity.
left terms and list operators (leftward)
left ->
nonassoc ++ --
right **
right ! ~ ~. \ and unary + and -
left =~ !~
left * / % x
left + - .
left << >>
nonassoc named unary operators
nonassoc isa
chained < > <= >= lt gt le ge
chain/na == != eq ne <=> cmp ~~
left & &.
left | |. ^ ^.
left &&
left || //
nonassoc .. ...
right ?:
right = += -= *= etc. goto last next redo dump
left , =>
nonassoc list operators (rightward)
right not
left and
left or xorDo not try to memorise it. Read it once now so the shape is familiar, then use §3 and §4, which are the parts that actually matter.
Chapter 1.14 covered reaching for perldoc; this table is one of the best reasons to have that habit. perldoc perlop is two seconds away and is always right about the Perl you are running.
3. Every Surprise in This Module Is a Row in That Table
Here is the payoff. Each thing that caught you in this module is one line of the table.
** sits above the unary minus
right **
right ! ~ ~. \ and unary + and -** is higher, so it binds first. That is why Chapter 3.2 measured -2 ** 2 as -4 — Perl read it as -(2 ** 2). And ** is marked right, which is why 2 ** 3 ** 2 is 512 rather than 64.
*, /, % and x share one row
left * / % xSame precedence, grouped left to right — which is Chapter 3.1's 18 / 20 * 100 giving 90. It also tells you that x binds as tightly as multiplication, so "ab" x 2 . "c" repeats before it joins:
use strict;
use warnings;
print "ab" x 2 . "c", "\n";ababcababc, not abcabc. x is on the row above ., so "ab" x 2 happened first.
|| is above the comma; or is below it
left || //
...
left , =>
...
left or xorThis is the single most valuable thing the table tells you, and it explains Chapter 3.9's measured defect exactly.
|| is above the comma row, so inside open my $fh, "<", $path || die ... it binds tighter than the commas and attaches to $path alone. or is below the comma row, so it binds looser than the whole argument list and takes the entire open ... call as its left operand. That is why one form works and the other silently exits zero.
= is above the comma, which is above and/or
right = += -= *= etc. goto last next redo dump
left , =>
...
left and
left or xor= is above or, so my $b = 0 or 5; groups as (my $b = 0) or 5 — Chapter 3.8's measurement. And || is above =, so my $a = 0 || 5; groups as my $a = (0 || 5) and works.
That is the whole of the and-versus-&& problem, in two rows.
4. The Four Rows That Bite
If you retain nothing else from the table, retain these.
| Remember | Because |
|---|---|
** is above unary minus, and is right associative | -2 ** 2 is -4; 2 ** 3 ** 2 is 512 |
&& || // are above = | my $x = $a || $b; works as intended |
and or not are below = | my $x = $a or $b; assigns $a and discards $b |
|| is above the comma; or is below it | open(...) or die works; open ... || die does not |
Everything else, parenthesise.
5. The Case for Parentheses You Do Not Need
($passed / $total) * 100 has exactly the same meaning as $passed / $total * 100. The parentheses are redundant. Write them anyway, and here is the argument.
The reader's cost is not symmetric with yours. You know what you meant when you wrote the line. A reviewer, or you in four months, has to either recall Perl's associativity or decide it is probably fine. The second is what happens at the end of a long review, and it is how Chapter 3.1's misgrouped percentage ships.
Redundant parentheses cost nothing at runtime. There is no performance argument against them.
They survive editing. When someone inserts a term into an expression, explicit grouping constrains where it can go. Implicit grouping silently re-associates around the new operator.
They mark the places you thought about. A line with deliberate parentheses tells a reader that the author considered the order. A line without them is ambiguous about whether the order was considered or merely survived.
The one caution is that parentheses can be overdone. ((($a))) and parenthesising every single term makes a line harder to read, not easier. The target is one level of grouping that makes the intended order visible:
my $rate = $passed / $total * 100; # correct, relies on the reader
my $rate = ($passed / $total) * 100; # correct, and says so <-- prefer
my $rate = (($passed) / ($total)) * 100; # correct, and noisy6. When Parentheses Are Not Enough
Two cases from this module where the fix is not a parenthesis.
A line that needs splitting. If an expression needs three levels of grouping to be readable, the real problem is that it is doing too much. Name an intermediate value:
my $ok = $count == $expected && $status eq "DONE" && $slack > 0;
my $counts_match = $count == $expected;
my $finished = $status eq "DONE";
my $timing_clean = $slack > 0;
my $ok = $counts_match && $finished && $timing_clean;The second version costs three lines and makes a failure diagnosable — you can print any of the three names to find out which condition was false. The first tells you only that the conjunction was false.
A print followed directly by a parenthesis. Chapter 3.2 §5 measured this: print (2 ** 3) ** 2; prints 8, because the parenthesis became print's argument list rather than a grouping. Adding more parentheses in the wrong place does not help; print +(2 ** 3) ** 2; or print ((2 ** 3) ** 2); is the fix, and use warnings reports the problem as print (...) interpreted as function.
That case is a useful reminder that a parenthesis immediately after a function name means arguments, everywhere in Perl.
7. Why This Matters in Engineering Work
Precedence bugs are the hardest class to catch in review because every token is correct. There is no misspelled variable, no wrong operator, no missing semicolon — just a grouping that differs from the author's intention. Reviewers check for things that look wrong, and these do not.
Two of them in this module exit zero. open ... || die reports success after failing to read its input, and my $limit = $arg or 10 assigns silently. A flow that reads exit status learns nothing in either case.
The cheap defence is a habit, not knowledge. Writing ($a / $b) * 100 does not require remembering which row / is on. It requires only the habit of grouping what you meant, which is why this chapter ends on the habit rather than on the table.
8. Common Mistakes
Trusting memory over perldoc perlop. The table is two seconds away and authoritative for your Perl.
Assuming and is && with nicer spelling. They are on different rows, either side of =.
Assuming ** groups left to right. It is the one right-associative arithmetic operator.
Forgetting that unary minus is weaker than **. -2 ** 2 is -4.
Writing print ( with a space and expecting grouping. The parenthesis becomes the argument list.
Attributing Chapter 3.10's x behaviour to precedence. The parentheses there change the operand's kind, not the grouping.
Removing redundant parentheses to tidy a line. They were load-bearing for the reader even when not for Perl.
9. Exercise
Exercise 1 — predict from the table. Without running them, use the table in §2 to predict each: 2 + 3 * 4, -3 ** 2, 2 ** 2 ** 3, 10 - 4 - 3, "ab" x 2 . "c". Then run all five and record any you got wrong, naming the row that decided it.
Exercise 2 — the two or-forms. Write my $x = 0 || 5; and my $y = 0 or 5; in one script, print both, and capture STDERR. Then point at the two rows in §2 that explain the difference.
Exercise 3 — the open idiom. Write both open(my $fh, "<", "/no/such") or die "a: $!\n"; and the broken open my $fh2, "<", "/no/such" || die "b: $!\n"; as separate scripts. Record the exit status of each and explain, using the comma row, why only one died.
Exercise 4 — parenthesise for a reviewer. Take my $util = $used / $total * 100; and my $ok = $a == $b && $c ne $d; and add the minimum parentheses that make the intended order visible without noise. Justify each pair you added in one clause.
Exercise 5 — split instead. Rewrite my $pass = $errors == 0 && $warnings < $limit && $status eq "DONE"; as named intermediate values, then add one line that reports which condition failed. State what that version gives you that the original does not.
Exercise 6 — look it up. Run perldoc perlop and find the precedence table. Report where ?: sits relative to =, and say what that means for my $x = $c ? 1 : 2;.
10. Summary
- Precedence decides which of two different operators applies first; associativity decides the order for two of the same precedence.
- The table in
perldoc perlopis authoritative for the Perl you are running. Look it up rather than recalling it. - Every grouping surprise in this module is one row of it —
**above unary minus and right associative,* / % xsharing a left-associative row, and the||/=/,/orordering. - Four rows cover almost every real defect, and §4 lists them.
("ab") x 3is not a precedence case — those parentheses change the operand from a string to a list.- Write the redundant parentheses. They cost nothing, survive editing, and spare the reader a lookup.
- When one level of grouping is not enough, name intermediate values instead of adding a third level — and you gain a diagnosable failure.
- A parenthesis straight after a function name is an argument list, which is why
print (...)behaves as it does.
That closes Module 3. You now have every operator family in Perl: arithmetic, string, assignment, both comparison families, the three-way comparisons, logic with its short-circuit behaviour, ranges and repetition, bitwise, and the rules that decide what order they apply in. Module 4 turns to the functions that work on strings, where these operators stop being the whole toolkit and start being the glue between calls.
Where this fits
Part of the Perl curriculum.
