Perl Part I · Module 3 · Operators and Expressions
Assignment Operators: += .= //= and Friends
Most of this chapter is convenience: += adds to a variable in place, .= appends to a string, and a dozen others follow the same pattern of taking an operator and gluing an equals sign to it. Then there is one pair that is not convenience at all. Both ||= and //= mean roughly 'set this if it has no value yet', they differ in what counts as having no value, and on a variable holding zero they give different answers. Since the numbers this trade cares about are error counts, violation counts and timing slacks — where zero is the result you were hoping for — picking the wrong one of those two silently replaces good news with a default. This chapter shows both running.
Foundation13 min readPerlPart IFundamentalsAssignmentOperators
Part I · Module 3 · Chapter 3.4 · Assignment Operators: += .= //= and Friends
1. Plain Assignment, Briefly
= you already have from Chapter 2.2: it evaluates the expression on its right and stores the result in the variable on its left. Chapter 3.1 added the detail that the right-hand side is reduced to a finished value before the store happens.
One thing worth adding: assignment is an expression, so it produces a value — the value that was assigned. That is why this works:
use strict;
use warnings;
my $a;
my $b;
$a = $b = 7;
print "a=$a b=$b\n";a=7 b=7$b = 7 stored 7 and produced 7, which $a = then stored. Chained assignment is occasionally handy and occasionally confusing; the reason to know it is that the underlying fact — assignment produces a value — explains §7's trap.
2. Compound Assignment
The compound forms take an operator and an =, and mean "apply this operator to the variable and store the result back".
use strict;
use warnings;
my $count = 0;
$count += 1;
my $summary = "marks: ";
$summary .= "72";
print "count=$count\n";
print "$summary\n";count=1
marks: 72$count += 1 is shorthand for $count = $count + 1, and $summary .= "72" for $summary = $summary . "72". Every arithmetic and string operator from the last two chapters has a compound form:
| Operator | Long form | Does |
|---|---|---|
+= | $x = $x + $y | add in place |
-= | $x = $x - $y | subtract in place |
*= | $x = $x * $y | multiply in place |
/= | $x = $x / $y | divide in place |
%= | $x = $x % $y | take the remainder in place |
**= | $x = $x ** $y | raise to a power in place |
.= | $x = $x . $y | append text in place |
x= | $x = $x x $y | repeat in place |
Two reasons to prefer the short form beyond typing less. The variable's name appears once, so a mistyped name is a compile error under use strict rather than a silent reference to the wrong variable. And when the name is long — $total_failing_endpoints += 1 — the long form puts the same long name twice on one line and invites a reader to check they match.
The compound forms also produce a value, like plain assignment:
use strict;
use warnings;
my $n = 5;
my $result = ($n += 3);
print "n=$n result=$result\n";n=8 result=8The variable became 8, and the expression ($n += 3) handed back 8 as well.
3. .= and Building Up a String
.= deserves a note because it is how reports get assembled. Rather than printing as you go, you accumulate:
use strict;
use warnings;
my $report = "";
$report .= "block : alu\n";
$report .= "tests : 184\n";
$report .= "failures: 7\n";
print $report;block : alu
tests : 184
failures: 7Note my $report = ""; rather than my $report;. Both produce the same text, and — this is worth measuring rather than assuming — neither warns:
use strict;
use warnings;
my $report;
$report .= "line one\n";
print $report;line oneNothing on STDERR. That is a deliberate exemption rather than an oversight. Plain concatenation on an undefined value does warn — Chapter 3.3 §5 showed "alu" . $suffix producing Use of uninitialized value — but .= and += do not, because starting an accumulator from nothing is a legitimate and common thing to want. Perl treats "append to a variable that is empty so far" as intentional.
So the reason to write = "" is not to silence a warning. It is to say "this begins empty on purpose" to the next reader, who otherwise has to decide whether the missing initialiser was a choice or an omission. That is the same argument Chapter 2.7 made for being explicit about undef.
4. The Pair That Matters: ||= and //=
Both of these mean approximately "give this variable a value if it does not have one". They differ in what having a value means, and the difference is the whole reason this chapter exists.
Both look identical on an undefined variable
use strict;
use warnings;
my $limit;
$limit //= 10;
print "limit=$limit\n";limit=10Replace //= with ||= there and you get limit=10 as well. On an undefined variable the two agree, which is exactly why the difference hides.
On a real zero they disagree
use strict;
use warnings;
my $with_dslash = 0;
my $with_or = 0;
$with_dslash //= 99;
$with_or ||= 99;
print "//= gave $with_dslash\n";
print "||= gave $with_or\n";//= gave 0
||= gave 99||= threw the zero away. //= kept it.
The reason is the two chapters that set this up. ||= asks is this value true? — and Chapter 2.8 established that 0 is false in Perl, so ||= concluded the variable needed a default and overwrote a perfectly good measurement. //= asks is this value defined? — and Chapter 2.7 established that 0 is defined, so //= left it alone.
//= needs Perl 5.10 or newer
The defined-or operators — // and //= — were added in Perl 5.10, released in 2007. On anything newer they are simply available, and the Perl on the machine these notes were written on is 5.34.1, where the examples above ran.
That is worth checking rather than assuming, because Chapter 1.2 made the point that the Perl on an engineering machine is whatever the machine has. If you need to guarantee the operator is present, say so in the file:
use strict;
use warnings;
use v5.10;
my $limit;
$limit //= 10;
print "limit=$limit\n";limit=10use v5.10; makes the requirement explicit and fails at compile time on an older Perl with a clear message, rather than failing confusingly at the //= itself. On a Perl too old to have it, the long form $limit = defined($limit) ? $limit : 10; does the same job — the conditional operator is Chapter 8.6's.
5. Compound Assignment Is Not a Continuous Relationship
Worth saying plainly, because the shorthand can read like one. $count += 1 is a single event: it reads the current value, adds one, stores the result, and finishes. It does not establish any ongoing rule that $count increases.
If you have been reading Chapter 2.2's note on hardware description languages, this is the same distinction. $total .= $line inside a loop appends once per iteration because the loop executes the statement repeatedly — not because the statement describes an accumulating relationship.
6. Why This Matters in Engineering Work
The ||= defect is real and quiet. It is worth stating the shape of it once more because it is the kind of bug that survives review: the code reads sensibly, the variable name is honest, no warning fires, and the output is a plausible string. The only way to catch it is to ask what the variable holds when everything went right — and the answer, for a count of bad things, is zero.
Accumulating with .= beats printing as you go when a report has to be written somewhere other than the terminal, or when you may decide not to emit it at all. A failure partway through leaves you holding a partial string in memory rather than a partial file on disk — and Chapter 3.2 §3 showed how easily a script dies partway through.
Prefer the compound form for long names. $total_failing_endpoints += 1 names the variable once. The long form names it twice, and a typo in the second copy is a different bug depending on whether use strict can see it.
7. = Is Not ==
These are different operators and Perl will not usually stop you from confusing them.
=assigns.$x = 5puts 5 in$xand produces 5.==compares two numbers.$x == 5produces true or false and changes nothing. Chapter 3.5 covers it.
The trap is that = produces a value, as §1 showed, so an assignment can sit where a test was intended and be perfectly legal:
use strict;
use warnings;
my $errors = 0;
if ($errors = 5) {
print "errors is 5\n";
}
print "errors is now $errors\n";errors is 5
errors is now 5Read what happened. The condition assigned 5 to $errors, produced 5, and 5 is true — so the branch ran, and $errors was destroyed on the way. The message is a lie: it says $errors is 5 because the line made it 5. And $errors was 0 before, which is the good value.
Perl did warn, and the warning is a good one:
Found = in conditional, should be == at assign-in-condition.pl line 6.That is use warnings from Chapter 1.11 earning its place again — it named the mistake, named the fix, and gave the line.
But the warning has a limit you need to know about. It fires when the right-hand side of the assignment is a constant. It does not fire when the right-hand side is a variable or an expression:
use strict;
use warnings;
my $errors = 0;
my $expected = 5;
if ($errors = $expected) {
print "branch ran\n";
}
print "errors is now $errors\n";branch ran
errors is now 5Silent. Perl allows an assignment in a condition because it is occasionally genuinely wanted, and once the right-hand side is not a literal it cannot distinguish your typo from your intent.
Notice which case got the warning. if ($errors = 5) is the version in a textbook; if ($errors = $expected) is the version in real code, where both sides are named values. The diagnostic covers the example and misses the one you are likely to write.
So the residual risk is yours to manage. Two habits: read every if condition looking specifically for a lone =, and choose == or eq deliberately rather than by reflex — which is what Chapter 3.5 is about to make you do anyway.
8. Common Mistakes
Using ||= on a count. A measured zero becomes the default. Use //= unless an empty value really is as bad as a missing one.
Assuming //= is available everywhere. It needs Perl 5.10 or newer. Say use v5.10; if it matters.
Writing my $report; before a .=. This does not warn — .= and += are exempt — so start from "" for the reader's sake rather than Perl's.
Writing = where you meant ==. It is legal and it assigns. use warnings catches it when the right-hand side is a constant and stays silent when it is a variable, so do not rely on the diagnostic alone.
Using the long form with a long variable name. $x = $x + 1 is fine; $total_failing_endpoints = $total_failing_endpoints + 1 is two chances to mistype one name.
Expecting += to set up an ongoing relationship. It is a single read-modify-store at the moment the statement runs.
9. Exercise
Exercise 1 — the zero. Write a script that sets two variables to 0, applies //= to one and ||= to the other with a default of 99, and prints both. Then explain each result in one sentence, naming the chapter that established the relevant property of 0.
Exercise 2 — the defect in context. Write my $violations = 0; followed by $violations ||= "not measured"; and print a one-line report. State what a timing engineer reading that report would conclude, and what was actually true.
Exercise 3 — build a report. Using .=, accumulate a three-line report into one variable and print it with a single print. Start from "", then change it to my $report; and run it again, capturing STDERR separately. Record whether a warning appeared, then do the same with plain concatenation — my $out = "pre" . $report; where $report is undefined — and explain why the two cases differ.
Exercise 4 — assignment as an expression. Predict the output of my $n = 10; my $r = ($n -= 4); print "$n $r\n"; and then run it. Say which value each variable holds and why they are the same.
Exercise 5 — find the =. Starting from my $retries = 3;, the line if ($retries = 0) { print "no retries left\n"; } never prints its message. Explain precisely why, say what $retries holds afterwards, record the warning Perl gives, and give the one-character fix. Then change the condition to if ($retries = $budget) with my $budget = 0; and say what happens to the warning.
10. Summary
- Assignment is an expression — it produces the value assigned, which is why
$a = $b = 7works. - Compound assignment (
+=,.=,*=, and the rest) applies an operator in place, names the variable once, and also produces a value. ||=and//=agree on an undefined variable and disagree on zero.||=tests truth and discards a real0;//=tests definedness and keeps it.- Use
//=for numbers where zero is meaningful — which, for error and violation counts, is always. //=requires Perl 5.10+.use v5.10;states the requirement..=and+=do not warn on an undefined variable — the exemption is deliberate — so initialise an accumulator to""for clarity, not to silence anything. Plain.does warn.=in a condition is legal. It assigns, usually tests true, and overwrites the variable you were asking about.use warningsreports it only when the right-hand side is a constant.
Chapter 3.5 is the most important chapter in this module: the two equality operators, why Perl needs both, and what happens when you reach for the wrong one.
Where this fits
Part of the Perl curriculum.
