Skip to content
VLSI Mentor

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.

Azvya Education Pvt. Ltd.VLSI Mentor
Captured output — recalled from Chapter 1.8
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.

Azvya Education Pvt. Ltd.VLSI Mentor
shadowing.pl — line 6 has my
use strict;
use warnings;

my $total = 0;
{
    my $total = 99;
    print "inside:  $total\n";
}
print "outside: $total\n";
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output
inside:  99
outside: 0
Azvya Education Pvt. Ltd.VLSI Mentor
reassignment.pl — line 6 has no my
use strict;
use warnings;

my $total = 0;
{
    $total = 99;
    print "inside:  $total\n";
}
print "outside: $total\n";
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output
inside:  99
outside: 99

Inside 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 $total went 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.
Three moments in the program, left to right. Before the block, the name total refers to the outer variable holding 0. Inside the block, the name refers to a second inner variable holding 99. After the block, the name refers to the outer variable again, still holding 0.before the block$total means the outer one0inside the block$total means the inner one99after the block$total means the outer one012
Figure 1 — a conceptual view of which variable the name $total refers to at three points in shadowing.pl. It shows name resolution, not memory layout: inside the block the name reaches the inner variable, and after the block it reaches the outer one again, whose value was never changed.

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:

Azvya Education Pvt. Ltd.VLSI Mentor
Captured output — two my declarations in one scope
"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 isWarning?Outer variable after the block
the same blockyes — "masks earlier declaration"n/a; there is no inner block
an inner blockno — silent and legalunchanged

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 my changes which variable a stage updates. If a stage appears to compute a result and the next stage sees the old value, look for a my inside 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

  1. my creates a name that exists from its declaration to the end of the enclosing block.
  2. That region is lexical scope, and it is determined by the text of the file rather than by what happens at run time.
  3. A my in an inner block creates a second variable and leaves the outer one untouched — shadowing.
  4. The same line without my assigns to the existing variable.
  5. Inner-block shadowing is silent; two my declarations in one block produce a warning.
  6. 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:

Azvya Education Pvt. Ltd.VLSI Mentor
Exercise 2 — predict both lines
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:

Azvya Education Pvt. Ltd.VLSI Mentor
Exercise 4 — why is the count still zero?
use strict;
use warnings;

my $error_count = 0;
{
    my $error_count = 2;
}
print "errors: $error_count\n";

10. Summary

  • my creates 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 my in 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.