Common Beginner Mistakes
A tour of the mistakes Perl beginners make most often, from forgetting strict and warnings to unescaped regex metacharacters.
Introduction
Every Perl programmer runs into the same handful of traps early on. Most of them are quick to explain and, once you have seen them once, easy to spot for the rest of your career. This lesson walks through the most common ones with concrete before-and-after examples.
Forgetting use strict and use warnings
Without these two pragmas, Perl silently allows typos to become new global variables, treats undef as 0 or an empty string without complaint, and generally makes it much harder to catch bugs early. There is essentially never a good reason to omit them, even in a five-line script.
use strict;use warnings;
my $total = 0;for my $n (1..5) { $total += $n;}print "Total: $total\n";Click Run to see what this code prints.
Scalar vs List Context Confusion
The same expression can behave completely differently depending on whether Perl evaluates it in scalar or list context. Assigning an array to a scalar gives its element count; assigning it to a parenthesized list of variables distributes the elements instead.
use strict;use warnings;
my @array = (1, 2, 3, 4, 5);
my $count = @array;my ($first) = @array;
print "Count: $count\n";print "First: $first\n";
my $wrong = (1, 2, 3);print "Wrong: $wrong\n";Click Run to see what this code prints.
(1, 2, 3) in scalar context uses the comma operator, which evaluates each item and discards it, keeping only the last one - a classic beginner trap when the parentheses look like they should build a list.
= vs == vs eq
Three different operators, three different jobs: = assigns, == compares numbers, and eq compares strings. Using = where you meant == is a classic bug, because if ($a = 10) is always true (it assigns 10, then evaluates the assignment's result as true) and silently overwrites $a in the process.
use strict;use warnings;
my $a = 5;my $b = '5';
if ($a == $b) { print "Numerically equal\n";}if ($a eq $b) { print "String equal too\n";}
if ($a = 10) { print "Oops, this always runs and now \$a is 10\n";}Click Run to see what this code prints.
Unescaped Regex Metacharacters
Characters like . $ ^ * + ? ( ) [ ] { } | all have special meaning inside a regex. If you want to match one of them literally, you must escape it with a backslash - otherwise the pattern matches far more than you intended.
use strict;use warnings;
my $price = '$19.99';
if ($price =~ /19.99/) { print "Matched loosely\n";}
if ($price =~ /\$19\.99/) { print "Matched precisely\n";}Click Run to see what this code prints.
An unescaped . matches any character, so /19.99/ happens to match "19.99" too - but it would also wrongly match "19x99". The escaped version /\$19\.99/ matches only the exact literal text.
Off-By-One Array Mistakes
Array indices are zero-based, and the last valid index is one less than the element count. The special variable $#array gives you that last index directly, which avoids constant off-by-one arithmetic.
use strict;use warnings;
my @colors = ('red', 'green', 'blue');
print "Last index: $#colors\n";print "Length: ", scalar(@colors), "\n";
my $oops = $colors[scalar(@colors)];print defined($oops) ? $oops : "undef", "\n";Click Run to see what this code prints.
Forgetting to chomp Input
Lines read from a filehandle (or from <STDIN>) keep their trailing newline. Comparing an unchomped line against a plain string almost always fails in a confusing way, because the newline makes the two values unequal even though they look identical when printed.
use strict;use warnings;
my $line = "hello\n";if ($line eq 'hello') { print "Matched\n";} else { print "No match - probably a trailing newline\n";}
chomp $line;print "Matched now: ", ($line eq 'hello' ? 'yes' : 'no'), "\n";Click Run to see what this code prints.
Quick Recap
- Skipping use strict and use warnings.
- Confusing scalar context and list context, especially with parenthesized lists.
- Using = instead of == or eq inside a condition.
- Forgetting to escape regex metacharacters like . and $.
- Off-by-one errors from misunderstanding array length versus last index.
- Comparing or splitting a line that was never chomped.
Best Practices
- Put use strict; use warnings; at the top of every single Perl file, no exceptions.
- When assigning from an array, be deliberate about scalar versus list context.
- Never write if ($var = value) - if you truly mean assignment, extract it to its own line first.
- Escape every regex metacharacter you want to match literally.
- Use $#array for the last index and scalar(@array) for the count - do not mix them up.
- chomp every line read from user input or a file before comparing or processing it.
Frequently Asked Questions
Because assignment is itself an expression that evaluates to the assigned value - useful in some idioms, like while (my $line = <$fh>), but risky when == was intended.
Yes - use strict and use warnings catch many of them at runtime, and static analysis tools like perlcritic can flag risky patterns before you even run the code.
Not directly, but it does warn about many related symptoms, such as using undef in a numeric context, which often points you toward the underlying context mistake.
Key Takeaways
- Always enable use strict and use warnings - there is no good reason not to.
- Scalar and list context can make the exact same expression behave very differently.
- =, ==, and eq each do a different job - mixing them up creates silent, hard-to-spot bugs.
- Regex metacharacters must be escaped to be matched literally.
- chomp is a small habit that prevents a surprising number of confusing bugs.
Summary
Every one of these mistakes is easy to make and, once you know what to look for, easy to catch in a code review or while debugging. The next lesson flips the perspective, focusing on the positive habits that keep Perl code clean and maintainable.