Best practice for declaring variables varies from programming language to programming language. But the declaration you used is very far from best practice in Perl.
When declaring a variable you in Perl, it is best practice to declare whether it's a lexical (my) or package (our) variable. e.g.:
my $counter = 0;
It's also best practice to declare the variable in the tightest possible scope. For example, if a variable is used inside a loop, and needs reinitialising each time round the loop, then declare it inside the loop, not before the loop.
Find the bug here:
use 5.010;
use strict;
my $gender = 'unknown';
while (<DATA>)
{
chomp;
given ($_) {
when ("Alice") { $gender = 'female' }
when ("Annie") { $gender = 'female' }
when ("Andy") { $gender = 'male' }
when ("Arnold") { $gender = 'male' }
}
say "$_ is $gender.";
}
__DATA__
Alice
Andy
Arnold
Jennifer
Annie
Henry
Output is:
Alice is female.
Andy is male.
Arnold is male.
Jennifer is male.
Annie is female.
Henry is female.
Why is Jennifer male? Why is Henry female? It's because $gender is declared outside the loop, so is allowed to stay alive between loop iterations. Merely moving the one line where it's declared solves our subtle bug:
use 5.010;
use strict;
while (<DATA>)
{
chomp;
my $gender = 'unknown';
given ($_) {
when ("Alice") { $gender = 'female' }
when ("Annie") { $gender = 'female' }
when ("Andy") { $gender = 'male' }
when ("Arnold") { $gender = 'male' }
}
say "$_ is $gender.";
}
__DATA__
Alice
Andy
Arnold
Jennifer
Annie
Henry
Alice is female.
Andy is male.
Arnold is male.
Jennifer is unknown.
Annie is female.
Henry is unknown.
Perl variables have some pretty cool features, but they can trip you up. The precaution of adding use strict near the top of each script is generally a wise one. This one line tells Perl to force you to declare all your variables. This doesn't stop you shooting yourself in the foot, but it makes it difficult to shoot yourself in the foot accidentally. (You're still able to shoot yourself in the foot if you put in a bit of effort.)
perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'
|