Perl Part I · Module 2 · Variables, Scalars, and Data Types
my and Lexical Scope
You have written my on every variable since Chapter 1.7 because use strict requires it. This chapter explains what it actually does: it creates a name that exists from that line to the end of the enclosing block, and nowhere else. That region is called lexical scope, and getting it right is what lets a three-hundred-line script avoid interfering with itself. The chapter turns on one comparison — a my inside a block creates a second variable and leaves the outer one untouched, while the same line without my changes the variable that already exists. Three characters apart, opposite results.
Foundation13 min readPerlPart IFundamentalsScopemy
Part I · Module 2 · Chapter 2.3 · my and Lexical Scope
1. What my Creates
my declares a variable. More precisely, it creates a name that Perl will recognise from the point of declaration to the end of the block containing it — and will not recognise anywhere else.
That region is the variable's scope. Perl's kind is called lexical scope, which means the region is decided by where the declaration sits in the text of your file. You can see a variable's scope by reading the file; you do not have to run anything to work it out.
Chapter 1.8 demonstrated the consequence: use a my variable after its block has closed and the program does not compile.
Global symbol "$inside" requires explicit package name (did you forget to declare "my $inside"?) at out-of-scope.pl line 7.
Execution of out-of-scope.pl aborted due to compilation errors.This chapter is about using that deliberately rather than merely avoiding the error.
2. The Comparison That Matters
Two programs. They differ only in whether line 6 begins with my.
use strict;
use warnings;
my $total = 0;
{
my $total = 99;
print "inside: $total\n";
}
print "outside: $total\n";inside: 99
outside: 0use strict;
use warnings;
my $total = 0;
{
$total = 99;
print "inside: $total\n";
}
print "outside: $total\n";inside: 99
outside: 99Inside the block both print 99. Outside, one is 0 and the other is 99.
- With
my, line 6 created a second, different variable that also happens to be called$total. It exists only inside the braces. When the block ended, it ceased to exist and the name$totalwent back to meaning the outer one — which had never been touched. This is called shadowing. - Without
my, line 6 was an ordinary assignment to the variable that already existed. There is only ever one$total, and it now holds 99.
3. Perl Does Not Warn About This
Worth stating plainly, because it is where the trap lies. Shadowing in an inner block is legal, idiomatic and silent — use warnings says nothing about it.
What Perl does warn about is declaring the same name twice in the same block, which Chapter 2.2 met in its final exercise:
"my" variable $error_count masks earlier declaration in same scope at ex4.pl line 5.So the two cases behave differently in a way that is easy to get backwards:
Where the second my is | Warning? | Outer variable after the block |
|---|---|---|
| the same block | yes — "masks earlier declaration" | n/a; there is no inner block |
| an inner block | no — silent and legal | unchanged |
The silent case is the one that produces a confusing bug: a value that you are certain you set, which is somehow still at its old value by the time you use it. The cause is almost always a stray my in an inner block.
4. Scope Is a Feature, Not a Restriction
So far this reads like a hazard. It is mostly the opposite: scope is what makes a long script safe to work on.
Because a my variable exists only in its block, two separate parts of a script can both use $count for their own purposes without any possibility of interference. You do not have to invent $count_for_the_second_part, and you do not have to read the whole file before choosing a name.
The practical habit that follows is worth adopting now:
Declare each variable in the smallest block that needs it.
A variable declared at the top of a long script is readable and writable by every line below it, which means any surprising value could have come from anywhere. The same variable declared inside the block that uses it can only have been set by the handful of lines you can see at once. That is the difference between a bug you find in a minute and one you find in an afternoon.
5. A Scope Does Not Have to Be a Bare Block
The bare { ... } used above is unusual in real code — Chapter 1.8 used it because it isolates the idea. In practice, blocks come attached to things:
- the body of an
if(Module 8) - the body of a loop (Module 9)
- the body of a subroutine (Module 10)
- the whole file, which is itself the outermost scope
Every one of those is a block, so every one of them bounds the my variables declared inside it. This is why the rule is worth learning before you meet any of them: when you reach loops in Module 9, a variable declared inside the loop body is fresh on every pass, and that follows from this chapter rather than from anything about loops.
6. Why This Matters in Engineering Work
This is where inherited Perl most often goes wrong, and it is worth being concrete.
The classic defect in a long legacy flow script is not a wrong algorithm. It is a variable whose scope is wider than its author intended, so one stage of the script reads a value that an earlier, unrelated stage left behind. Everything looks correct in isolation; the fault is that two parts of the file were never as separate as they appeared.
Two consequences for reading such a script:
- "Where is this value set?" is a scope question. The answer is "somewhere in the enclosing block", and the smaller that block, the shorter the search. When the block is the whole file, the honest answer is "anywhere above this line".
- A stray
mychanges which variable a stage updates. If a stage appears to compute a result and the next stage sees the old value, look for amyinside the first stage's block before suspecting the logic.
The habit from §4 is the defence, and it costs nothing to apply while writing.
7. Common Mistakes
A stray my in an inner block. The outer variable never changes and nothing warns. Symptom: a value you are sure you set is stale at the point of use. This is the most consequential mistake in the chapter.
Declaring inside a block and using it outside. A compile error, as §1 recalled. The message mentions Global symbol, which sounds unrelated to scope until you have seen it once.
Two my declarations in one block. Warns, and the later one wins. Usually a sign of code assembled from two places.
Declaring everything at the top of the file. Not an error, and it quietly removes the protection scope exists to give you. Prefer the smallest block that works.
Assuming indentation defines scope. It does not — Chapter 1.8 covered this. Only braces do. Badly indented code can look like it is inside a block when it is not, and the braces are what Perl reads.
8. What You Should Be Able to Say Now
mycreates a name that exists from its declaration to the end of the enclosing block.- That region is lexical scope, and it is determined by the text of the file rather than by what happens at run time.
- A
myin an inner block creates a second variable and leaves the outer one untouched — shadowing. - The same line without
myassigns to the existing variable. - Inner-block shadowing is silent; two
mydeclarations in one block produce a warning. - Declaring in the smallest block that needs the variable is what makes a long script safe to change.
9. Exercise
Exercise 1 — run both halves. Create shadowing.pl and reassignment.pl from §2 exactly as written and run both. Record the four lines of output and state, in one sentence, which three characters account for the difference.
Exercise 2 — predict, then verify. Before running it, write down both printed values for this program, then check:
use strict;
use warnings;
my $count = 1;
{
my $count = 2;
{
$count = 3;
}
print "middle: $count\n";
}
print "outer: $count\n";Explain which variable the innermost assignment changed, and why.
Exercise 3 — produce the compile error. Write a script that declares a variable inside a bare block and prints it after the block. Record the message, and say which stage it came from using Chapter 1.5.
Exercise 4 — fix a stale value. This script should print errors: 2 and prints errors: 0. Find the fault, explain it in terms of scope, and fix it with a one-word change:
use strict;
use warnings;
my $error_count = 0;
{
my $error_count = 2;
}
print "errors: $error_count\n";10. Summary
mycreates a name bounded by its block — from the declaration to the closing brace, and nowhere else.- Lexical means readable from the file. You can determine a variable's scope without running the program.
- A
myin an inner block shadows: a second variable is created and the outer one is left alone. - Without
my, the same line assigns to the variable that already exists. That is the whole difference. - Shadowing in an inner block is silent; redeclaring in the same block warns. The silent case is the one that bites.
- Declare in the smallest block that needs it — scope is the main defence against a long script interfering with itself.
Chapter 2.4 turns to what a scalar can actually hold, starting with numbers — including one place where Perl's arithmetic is not quite what the printed answer suggests.
Where this fits
Part of the Perl curriculum.
