Perl Part I · Module 3 · Operators and Expressions
Expressions and Evaluation Order
Module 2 was about values. This module is about the operators that combine them, and it starts with the skill the rest of it depends on: reading an expression the way Perl reduces it, one step at a time, instead of looking at a line and guessing what it produces. The demonstration is deliberately small — the same three numbers and the same two operators, grouped two different ways, giving 90 and 0.009. Once you can write down the intermediate values of a line, every operator chapter that follows becomes a question of which rules apply rather than a mystery about what the line does.
Foundation11 min readPerlPart IFundamentalsExpressionsEvaluation
Part I · Module 3 · Chapter 3.1 · Expressions and Evaluation Order
1. What an Expression Is
An expression is any piece of code that produces a value. All of these are expressions:
42— a literal produces itself.$seed— a variable produces the value it holds.$passed / $total— two values and an operator produce a third.
An operator is the thing that combines values; the values it combines are its operands. In $passed / $total, the operator is / and the operands are the two variables.
The reason this vocabulary is worth having is that Perl does not execute an expression so much as reduce it. A line containing several operators becomes one value through a series of steps, and being able to write those steps down is the difference between knowing what a line does and hoping.
2. The Right-Hand Side Becomes a Value First
Start with the shape you have used since Chapter 2.2:
use strict;
use warnings;
my $passed = 18;
my $total = 20;
my $rate = $passed / $total * 100;
print "$rate\n";90Line 6 does two separate things in a fixed order:
- Reduce
$passed / $total * 100to a single value. - Store that value in
$rate.
The assignment is the last thing that happens. Nothing is stored while the expression is still being worked out, and $rate has no partial value at any point — a fact worth holding onto, because it is why Chapter 2.2 could say that = copies a finished value.
3. Grouping Decides the Answer
Here is why tracing matters. The same tokens, grouped differently:
use strict;
use warnings;
print 18 / 20 * 100, "\n";
print 18 / (20 * 100), "\n";90
0.009Two answers, four orders of magnitude apart, from the same three numbers and the same two operators. The only difference is which operation happened first.
/ and * have the same precedence, so Perl groups them left to right — the property called associativity. 18 / 20 * 100 is therefore (18 / 20) * 100, and the parentheses in the second line override that grouping.
Precedence and associativity in full belong to Chapter 3.12. What you need here is the habit of asking which operation happens first, because that question has an answer and guessing has a 50% success rate.
4. Tracing, as a Method
Write the intermediate values down. For 18 / 20 * 100:
| Step | Expression | Value |
|---|---|---|
| start | 18 / 20 * 100 | — |
| group by associativity | (18 / 20) * 100 | — |
| 1 | 18 / 20 | 0.9 |
| 2 | 0.9 * 100 | 90 |
| store | $rate = 90 | 90 |
And for the parenthesised version:
| Step | Expression | Value |
|---|---|---|
| start | 18 / (20 * 100) | — |
| 1 | 20 * 100 | 2000 |
| 2 | 18 / 2000 | 0.009 |
Three lines of table, and the result is no longer a surprise. This is the single most useful thing in the chapter: when a line produces a number you did not expect, do not re-read it looking for a typo — reduce it on paper. The step where your expected value diverges from the real one is the step whose rule you had wrong.
5. An Expression Does Not Have to Be Stored
A value that is produced and not stored is simply discarded. That is legal and occasionally useful:
use strict;
use warnings;
my $cycles = 1_000;
print $cycles * 2, "\n";
print "$cycles\n";2000
1000$cycles * 2 produced 2000, which print wrote out. $cycles itself is untouched — it still holds 1000. An operator produces a new value; it does not modify its operands.
That last sentence has one important family of exceptions, the compound assignment operators such as +=, which exist precisely to update a variable in place. Chapter 3.4 covers them, and the distinction between "produces a value" and "changes a variable" is worth keeping clear from the start.
6. Why This Matters in Engineering Work
A pass rate, a utilisation figure, a cycles-per-transaction number — each is a small arithmetic expression, and each is read by someone who will act on it.
The characteristic failure is not a wrong operator but a wrong grouping, and it is almost invisible in review because every token on the line is correct. A line computing a percentage as $passed / $total * 100 is right; the same line written $passed / ($total * 100) is wrong by a factor of a hundred, looks equally plausible, and produces a number — 0.009 rather than 90 — that a reader may well accept as "some small fraction".
Two habits follow, and they are cheap:
- Trace any expression whose result you are about to publish. One table, two minutes, before the number reaches a report.
- Add parentheses that are not strictly required.
($passed / $total) * 100has the same meaning as the original and removes the need for the reader to know Perl's associativity rules. Chapter 3.12 makes the case properly.
7. Common Mistakes
Guessing instead of grouping. The fix is §4: reduce it step by step and find the step where your expectation and Perl's rule diverge.
Assuming an operator changes its operands. $cycles * 2 leaves $cycles alone. Only assignment — plain or compound — changes a variable.
Reading a long expression as a sequence of instructions. It is a reduction to one value, not a series of steps that each do something. That is why intermediate values have no names unless you give them some.
Trusting that a plausible number is a correct one. 0.009 is a perfectly plausible fraction and was produced by a misgrouped expression. The number's plausibility is not evidence.
8. Exercise
Exercise 1 — trace before running. Build the §4 table for 100 - 20 / 4 by hand, predicting the final value, then run print 100 - 20 / 4, "\n"; and compare. If you were wrong, name the step where your rule differed from Perl's.
Exercise 2 — make the grouping explicit. Rewrite 18 / 20 * 100 with parentheses so that it keeps its current meaning, and then again so that it means the other thing. Run both and confirm you get 90 and 0.009.
Exercise 3 — the pass rate. Write a script with my $passed = 47; and my $total = 50; that prints the pass rate as a percentage. Verify the number is 94, then deliberately misgroup it and record what gets printed instead.
Exercise 4 — explain a review comment. A colleague's line reads my $avg = $total_cycles / $runs * 2; and they say it computes "the average doubled". Trace it, say whether their description matches what Perl does, and state what you would change so that the code and the comment cannot disagree.
9. Summary
- An expression produces a value, and a line with several operators is reduced to one value step by step.
- An assignment's right-hand side is finished before the store happens.
- Grouping decides the answer. Operators of equal precedence group by their associativity —
/and*left to right. - Trace, do not guess. A three-line table turns a surprising result into a located rule.
- Operators do not modify their operands; only assignment does.
- A plausible number is not a correct number — misgrouped arithmetic produces believable wrong answers.
Chapter 3.2 takes the arithmetic operators this chapter borrowed and covers them properly, including three behaviours that catch people: what / returns, what % does with a negative operand, and which way ** groups.
Where this fits
Part of the Perl curriculum.
