Basics: Item 1: Know Your Namespaces
Basics: Item 1: Know Your Namespaces
Basics: Item 1: Know Your Namespaces
If you are experienced in other languages but new to Perl, you are probably
still discovering Perl’s idiosyncracies. This section deals with some of
those idiosyncracies. In particular, it addresses those that can bedevil
newly minted Perl programmers who are still attuned to other languages.
For example, you should already know that Perl’s variables are generally
made up of some piece of punctuation like $ or @ followed by an identifier.
But do you know whether different types of variables with the same name,
such as $a and @a, are completely independent of one another? They are—
see Item 1.
You should know that @a is an array, but do you know the difference
between $a[$i] and @a[$i]? The latter is a slice—see Item 2.
You should know that the number 0 is false, and that the empty string, "",
is false, but do you know whether the string consisting of a single space,
" ", is false? It’s true—see Item 5.
If you are a more experienced Perl programmer, these first few Items will
be mostly review for you. However, you may find some interesting details
toward the end of some Items in this section.
http://www.effectiveperl.com
10 Item 1 Basics
Also, each package (see Item 42) in a Perl program defines its own set of
namespaces. For example, $a in package main is independent of $a in
package foo:
You have to look to the right as well as the left of an identifier, as Perl does,
to determine what kind of variable the identifier refers to. For example,
the syntax for accessing elements of arrays and hashes begins with $, not @
or %. The $ means that the result is a scalar value, not that you are refer-
ring to a scalar variable:
$a = 1; Set scalar $a = 1.
@a = (1, 2, 3); Set array @a = (1,2,3).
%a = ('a' => 97, 'b' => 98); Set hash %a.
Not all variable-like things in Perl are prefixed with punctuation charac-
ters. Subroutine names can be prefixed with an ampersand, but the
ampersand is generally optional. In some cases, parentheses around the
subroutine arguments can also be omitted:
Filehandles, format names, and directory handles are not prefixed with
punctuation characters, but are recognized in context:
The filehandle, format name, and dirhandle below are independent of one
another, even though they are all named TEST.
It’s not necessarily bad programming style to take advantage of Perl’s inde-
pendent namespaces by giving two different kinds of variables the same
name. Sometimes it even seems like the sensible thing to do:
http://www.effectiveperl.com
12 Item 2 Basics
A slice has all the characteristics of a list of variable names. You can even
use it on the left-hand side of an assignment expression, or in other places
where an lvalue is required:
Now, @a[1] is as much a slice as are @a[1, 2], @a[2, 10], @a[5, 3, 1],
@a[3..7], and so on. @a[1] is a list, not a scalar value. It is a list of one
element.
These single-element slices are something you should watch out for. They
are dangerous critters if not used properly. A slice used in a scalar context
returns the last value in the slice, which makes single-element slices work
like scalar values, in some cases. For example:
Probably what was intended here was $jolly = $giant[3]. The sin-
gle-element slice @giant[3] is still OK, sort of, since @giant[3] in a scalar
context evaluates to its last (and in this case only) element, $giant[3].
Although single-element slices work somewhat like array elements on the
right side of assignments, they behave very differently on the left-hand side
of assignments. Because a single-element slice is a list, an assignment to a
single-element slice is a list assignment, and thus the right-hand side of
the assignment is evaluated in a list context. Unintentionally evaluating an
operator in a list context can produce dramatic (and unfortunate) results.
A good example is the line input operator, <filehandle>:
This reads all the lines from standard input, assigns the first one to ele-
ment 0 of @info, and ignores the rest! Assigning <STDIN> to @info[3] eval-
uates <STDIN> in a list context. In a list context, <STDIN> reads all the lines
from standard input and returns them as a list.
One more difference between slices and elements is that the expression in
the brackets of an element access is evaluated in a scalar context, whereas
for slices it is evaluated in a list context. This leads to another example of
bizarre behavior that is more difficult to explain:
Suppose you want to add an additional line containing 'EOF' to the end of the array
@text. You could write this as $text[@text] = 'EOF'. But don’t write @text[@text]
instead.
The array @text inside the brackets above is interpreted in a list context.
In a scalar context it returns the number of elements in @text, but in a list
context it returns the contents of the array itself. The result is a slice with
as many elements are there are lines.
The contents of the lines are interpreted as integer indices—if they’re text
they will likely all turn out to be zero, so the slice will look like @text[0,
0, 0, 0, 0, ...]. Then 'EOF' is assigned to the first element of the slice,
and undef to all the rest, which means that this will probably just over-
write the first element of @text with undef, leaving everything else alone.
What a mess!
Get in the habit of looking for single-element slices like @a[0] in your pro-
grams. Single-element slices are generally not what you want (though
they’re handy for tricks now and then), and a single-element slice on the
left-hand side of an assignment is almost certainly wrong. The -w com-
mand line option (see Item 36) will flag many suspect uses of slices.
($uid, $gid) = (stat $file)[4, 5]; Get user and group id from
result of stat $file.
http://www.effectiveperl.com
14 Item 2 Basics
However, slices can be put to some pretty interesting (and weird) uses. For
example:
Given two parallel arrays @uid and @name, this example sorts @name according to the
numerical contents of @uid.
You can use hash slices to create hashes from two lists, to overlay the con-
tents of one hash onto another, and to “subtract” one hash from another:
Uninitialized array variables, however, have the value (), the empty list. If
you assign undef to an array variable, what you actually get is a list of one
element containing undef:
The simplest way to avoid this is to assign the empty list () to array vari-
ables when you want to clear them. You can also use the undef verb:
The defined operator is the only way to distinguish undef from 0 and the
empty string ''. The defined operator will work on any value—in earlier
versions of Perl it would work only on lvalues, but that is no longer the
case.
http://www.effectiveperl.com
16 Item 3 Basics
%nuked = (U => '235', Pu => 238); %nuked has two key-value pairs.
undef %nuked; “Nuked” it—completely gone.
if (keys %nuked) { ... } FALSE
if (defined %nuked) { ... } Also FALSE, because %nuked is
completely gone.
0 < 5 TRUE
10 == 10.0 TRUE
10 <=> 9.5 1—“spaceship” operator.
The spaceship operator <=>1 is like cmp, except that it compares its
arguments numerically.
String comparison operators should not be used for comparing numbers,
because they don’t compare numbers properly. (Unless your definition of
“properly” puts "10" before "2".) The same applies for numeric operators
used to compare strings:
http://www.effectiveperl.com
18 Item 5 Basics
$hacker = 'joebloe';
if ($user == $hacker) { WRONG—== used on strings.
deny_access(); Oops—most strings look like 0
} to ==, so nobody gets on.
Perl’s sort operator uses string comparisons by default. Don’t use string
comparisons to sort numbers! See Item 14 for more about sorting.
▼ Don’t test for falsehood when you should be testing for undef.
The code in this example works well almost all of the time. Each time
through the loop, the fileglob <*> produces another filename from the cur-
rent directory, which goes into $file. Once all the filenames in the direc-
tory have been enumerated, <*> returns undef, which appears to be the
empty string and therefore false, causing the while loop to terminate.
You may also need to use a different strategy when testing to see if an ele-
ment is present inside a hash. undef is a perfectly acceptable value in a
hash:
http://www.effectiveperl.com
20 Item 6 Basics
$n = 0 + "123"; 123
$n = 0 + "123abc"; Also 123—trailing stuff ignored.
$n = 0 + "\n123"; Also 123—leading whitespace.
$n = 0 + "a123"; 0—no number at beginning.
The conversion process does not recognize octal or hexadecimal. Use the
oct operator to convert octal or hexadecimal strings:
2. Well, sort of. Perl prefers to use gconvert(). This is one of the reasons you
shouldn’t mess with $# any more.
$a = 123;
$b = 234;
$c = $a & $b; number 106
$a = "$a";
$b = "$b";
$d = $a & $b; string "020"
http://www.effectiveperl.com
http://www.effectiveperl.com