Basics: Item 1: Know Your Namespaces

Download as pdf or txt
Download as pdf or txt
You are on page 1of 14

Basics

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.

Item 1: Know your namespaces.


There are seven separate kinds of variables or variable-like things in Perl:
scalar variables, array variables, hash variables, subroutine names, for-
mat names, filehandles, and directory handles.
Each of these different kinds of variables has its own namespace. Chang-
ing the value of one kind of variable does not in any way affect the value of
another kind of variable with the same name. For example, the scalar vari-
able $a is independent of the array variable @a:

$a = 42; Set scalar $a = 42.

http://www.effectiveperl.com
10 Item 1 Basics

@a = (1, 2, 3); @a = (1,2,3), but $a is still 42.

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:

$a = 1; Assuming we start in package


main, set scalar $main::a = 1.

package foo; Default package is now foo.

$a = 3.1416; $foo::a is 3.1416; $main::a is


still 1.

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.

$a[3] = 4; $a is still 1; @a is (1,2,3,4) now.


$a{'c'} = 99; $a, @a still the same; %a has
three key-value pairs now.

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:

sub hi { A subroutine named hi.


$name = shift; "hi, $name\n"
}

print &hi("Fred"); The “old-style” syntax.

print hi("Fred"); Parens following hi cause it to


be recognized as a sub name.

print hi "Fred"; Parens can also be omitted if


hi is defined in the source code
before it is used (see Item 10).

Filehandles, format names, and directory handles are not prefixed with
punctuation characters, but are recognized in context:

from Effective Perl Programming, by Joseph N. Hall with Randal L. Schwartz


Avoid using a slice when you want an element. 11

The filehandle, format name, and dirhandle below are independent of one
another, even though they are all named TEST.

open TEST, "$$.test"; Open filehandle named TEST.


print TEST "test data\n"; Print to filehandle TEST.

format TEST = Format named TEST.


@<<<<<<<<<<<<< @<<<< @<<<<
$name, $lo, $hi
.

opendir TEST, "."; Directory handle 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:

@who = @who contains output from who


grep { /\bjoebloe\b/ } `who`; command, one line per element.

foreach $who (@who) { Iterate over each line of output


# ... do something with $who using variable $who.
}

Item 2: Avoid using a slice when you want


an element.
Is @a[1] an array element? Or an array slice?
It’s a slice.
One of the counterintuitive things encountered by people just beginning to
learn Perl is the difference between array elements and array slices. Even
after you know the difference, it’s not hard to type @ instead of $.
An introductory book or course about Perl will typically begin by telling
you that scalar variable names begin with $, and array variable names
begin with @. This is, of course, an oversimplification, which is corrected
in the next step of the introduction, where you learn that to access element
$n of array @a, you use the syntax $a[$n], not @a[$n]. This may seem
peculiar. However, it is a consistent syntax. Scalar values, not variables,
begin with $, even when those values come from an array or hash.
Therefore, @a[$n] doesn’t mean element $n of array @a. Rather, it is some-
thing different, called a slice. A slice is a shortcut way of writing a list of
elements:

@giant = qw(fee fie foe fum); @giant is ('fee', 'fie', 'foe',


'fum').

http://www.effectiveperl.com
12 Item 2 Basics

@queue = ($giant[1], $giant[2]); @queue is ('fie', 'foe').


@queue = @giant[1, 2]; Same thing, using a slice.

@fifo = (1, 2); Same thing again, using a list of


@queue = @giant[@fifo]; values in an array.

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:

($giant[1], $giant[2]) = @giant is ('fee', 'tweedle',


("tweedle", "dee"); 'dee', 'fum').

@giant[1, 2] = ("tweedle", "dee"); Same thing, assigning to a slice.

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:

$jolly = @giant[3]; $jolly = 'fum', but for the


wrong reason.

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>:

▼ Don’t use a single-element slice as the left-hand side of an assignment.

What was intended was $info[0] = <STDIN>.

@info[0] = <STDIN>; OOPS! <STDIN> in a list context!

($info[0]) = <STDIN>; Same problem w/o slice.

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-

from Effective Perl Programming, by Joseph N. Hall with Randal L. Schwartz


Avoid using a slice when you want an element. 13

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:

▼ Don’t confuse slices and elements.

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.

chomp (@text = <STDIN>); Read lines into @text. So far, so


good.
@text[@text] = 'EOF'; Seriously wrong! See below.

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.

Slicing for fun and profit


Beginning Perl programmers generally do not (intentionally) use slices,
except to select elements from a result:

($uid, $gid) = (stat $file)[4, 5]; Get user and group id from
result of stat $file.

$last = (sort @list)[-1]; Find the element of @list that


comes last in ASCII order
(inefficient for long @list).

http://www.effectiveperl.com
14 Item 2 Basics

$field_two = (split /:/)[1]; Get the second element from the


result of splitting $_ on :.

However, slices can be put to some pretty interesting (and weird) uses. For
example:

@list[5..9] = reverse @list[5..9]; Reverse elements 5 through 9 of


@list.

@list[reverse 5..9] = @list[5..9]; There’s more than one way to


do it.

They make a handy way to swap two elements:

@a[$n, $m] = @a[$m, $n]; Swap $a[$m] and $a[$n].

@item{'old', 'new'} = Swap $item{old} and


@item{'new', 'old'}; $item{new}.

Slices are also used in sorting (see Item 14):

■ Use slices to reorder arrays.

Given two parallel arrays @uid and @name, this example sorts @name according to the
numerical contents of @uid.

@name = @name[ Sort indices 0..$#name


sort {$uid[$a] <=> $uid[$b]} 0..$#name according to @uid, then use the
]; result to reorder @name.

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:

■ Use slices to create and manipulate hashes.

@char_num{'A'..'Z'} = 1..26; Create a hash from the keys


'A'..'Z' and values 1..26.

@old{keys %new} = values %new; Overlay the contents of %new on


%old.

%old = (%old, %new); Another (probably less efficient)


way of writing the above.

delete @name{keys %invalid}; “Subtract” elements in


%invalid from %name.

foreach $key (keys %invalid) { Another more verbose way of


delete $name{$key}; writing the above.
}

from Effective Perl Programming, by Joseph N. Hall with Randal L. Schwartz


Don’t assign undef when you want an empty list. 15

Item 3: Don’t assign undef when you want an


empty list.
Uninitialized scalar variables in Perl have the value undef. You can reset
scalar variables to their “pristine” state by assigning undef to them, or by
using the undef operator:

$toast = undef; It’s toast.

undef $history; It’s history.

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:

▼ Don’t assign undef to an array variable.

@still_going = undef; WRONG—@still_going =


(undef).
if (@still_going) { ... } Therefore this is TRUE.

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:

@going_gone = (); @going_gone = empty list, so


if (@going_gone) { ... } scalar(@going_gone) = 0 =
FALSE.

undef @going_gone; Now it’s really gone.


if (defined(@going_gone)) { ... } FALSE

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.

if (defined($a)) { ... } TRUE if $a is not undef.


if (defined(0)) { ... } TRUE; error in Perl 4.

if (defined(@a)) { ... } TRUE if @a is initialized.


if (defined(())) { ... } TRUE; error in Perl 4.

You can assign undef to an element of an array:

$puka[3] = undef; “Puka” is Hawaiian for “hole.”


@puka[1, 5, 7] = (); Create more holes.
@puka[0..99] = (); 100 copies of undef.

http://www.effectiveperl.com
16 Item 3 Basics

Note that undef is a perfectly reasonable element value. You cannot


shorten an array by assigning undef values to elements at the end of the
array. To actually shorten an array without assigning a whole new value to
it, you must assign to $#array_name or use one of the array operators like
splice or pop.

@a = 1 .. 10; @a has 10 elements.


$a[9] = undef; @a still has 10.
print scalar(@a), "\n"; "10"—(1..9, undef)

$val = pop @a; @a now has 9 elements: (1..9).


print scalar(@a), "\n"; "9"—(1..9)

splice @a, -2; Splice off the last 2 elements.


print scalar(@a), "\n"; "7"—(1..7)

$#a = 4; Shorten @a to 5 elements.


print scalar(@a), "\n"; "5"—(1..5)

Hashes and undef


The remarks above also apply to hashes. As with arrays, you cannot undef
a hash by assigning undef to it. In fact, assigning any list with an odd num-
ber of elements to a hash results in a warning message (at least in newer
versions of Perl). You can assign the empty list () to create an empty hash,
or you can use the undef operator to reset the hash to a pristine state.

%gone = (); %gone now contains no keys.


if (keys %gone) { ... } FALSE

%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.

As with arrays, you cannot shorten or remove elements from a hash by


assigning undef values to them. In order to remove elements from a hash
you must use the delete operator. The delete operator can be used on
hash slices as well as single elements:

■ Use delete to remove key-value pairs from hashes.

%spacers = ( Some sample data.


husband => "george", wife => "jane",
daughter => "judy", son => "elroy"
);

from Effective Perl Programming, by Joseph N. Hall with Randal L. Schwartz


String and numeric comparisons are different. 17

■ Use delete to remove key-value pairs from hashes. (cont’d)

delete $spacers{'husband'}; husband/george is gone.


if (exists $spacers{'husband'}) { ... } FALSE

delete @spacers{'daughter', 'son'}; daughter/judy and son/elroy


are gone.

Item 4: String and numeric comparisons are


different.
Perl has two completely different sets of comparison operators, one for
comparing strings and one for comparing numbers. It’s worthwhile to
know the difference and to keep them straight, because using the wrong
comparison operator can be the source of hard-to-find bugs.
The operators used to compare strings are made up of letters and look
like words, or like FORTRAN. Strings are compared “ASCIIbetically”—that
is, by comparing the ASCII values of the characters in the strings, includ-
ing case, spaces, and the like:

'a' lt 'b' FALSE


'a' eq 'A' FALSE—capitalization.
"joseph" eq "joseph " FALSE—spaces count.
"H" cmp "He" -1—cmp operator.

The cmp operator does a string comparison and returns -1, 0, or 1,


depending on whether its left argument is less than, equal to, or greater
than its right argument, respectively. It is particularly useful for sorting
(see Item 14).
Numeric comparison operators are made up of punctuation and look like
algebra, or like C:

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:

1. Is it Darth Vader’s fighter? Or a starbase from the old character-based Star


Trek games? You decide.

http://www.effectiveperl.com
18 Item 5 Basics

'10' gt '2' FALSE—'1' sorts before '2'.


"10.0" eq "10" FALSE—different strings.
'abc' == 'def' TRUE—both look like 0 to ==.

The kind of mistake this leads to is:

▼ Don’t compare strings with numeric operators, or vice versa.

$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.

Item 5: Remember that 0 and "" are false.


Because numeric and string data in Perl have the same scalar type, and
because Boolean operations can be applied to any scalar value, Perl’s test
for logical truth has to work for both numbers and strings.
The basic test is this: 0 and the empty string are false. Everything else is
true.
More precisely, when a quantity is used in a “Boolean context” (a term
sometimes used to refer to conditionals in control expressions, the ?:
operator, ||, &&, etc.), it is first converted to a string (see Item 6). The
string result is then tested. If the result is the empty string, or a string con-
sisting exactly of the single character "0", the result is “false.” Otherwise,
the result is “true.” Note that this rule means that undef will evaluate as
false, because it always looks like the number 0 or the empty string to
everything except the defined operator. This generally works very well. If
problems do arise, they are usually the result of testing a quantity to see if
it is false when really it should be tested to see if it is undef:

▼ Don’t test for falsehood when you should be testing for undef.

while ($file = <*>) { WRONG—what about a file


do_something($file); named "0"?
}

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.

from Effective Perl Programming, by Joseph N. Hall with Randal L. Schwartz


Understand conversions between strings and numbers. 19

There is one problem, though. If there is a file named 0 in the current


directory, it also appears to be false, causing the loop to terminate early.
To avoid this, use the defined operator to test specifically for undef:

■ Use the defined operator to test for undef.

while (defined($file = <*>)) { CORRECT—loop now


do_something($file); terminates only when <*>
} returns undef.

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:

Suppose %hash is undefined to start.

if ($hash{'foo'}) { ... } FALSE


if (defined($hash{'foo'}) { ... } Also FALSE.

$hash{'foo'} = undef; Assign an undef value.


if (defined($hash{'foo'}) { ... } Still FALSE.
print keys %hash; ('foo')

The exists operator can determine whether a particular key is present,


even if the corresponding value in the hash is undef:

Continued from above:

if (exists($hash{'foo'}) { ... } TRUE

Item 6: Understand conversions between strings


and numbers.
Perl’s scalar variables can contain either string or numeric data. They can
also contain both at the same time, usually as the result of converting
string data to a number, or vice versa.
Perl automatically converts values from numeric to string representation,
or vice versa, as required. For example, if a string appears next to a
numeric operator like +, Perl converts the string value to a number before
proceeding with the arithmetic. Or, if a number is the object of a pattern
match, Perl first converts the number to a string. Places where strings are
expected are referred to as string contexts, and places where numbers are
expected are referred to as numeric contexts. These are nice terms to
know, but we won’t use them very often in this book, since it rarely makes
any real difference.

http://www.effectiveperl.com
20 Item 6 Basics

The function used for converting numbers to strings is the C standard


library’s sprintf(), with a format of "%.15g" or something similar. 2 You
can change this format by changing the special variable $#, but the use of
$# is deprecated. If you need to use a particular format, use Perl’s
sprintf:

$n = sprintf "%10.4e", 3.1415927; "3.1416e+00"

The function used for converting strings to numbers is the C standard


library’s atof(). Any leading white space is ignored. Conversion uses
whatever leading part of the string appears number-like, and the rest is
ignored. Anything that doesn’t look like a number is converted to zero. For
example:

$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:

$n = 0 + "0x123"; 0—looks like number 0.


$n = 0 + oct("0x123"); 291—oct converts octal and hex
strings to decimal.

print "mode (octal): "; Prompt for file mode.


chmod <STDIN>, $file; WRONG—string from STDIN
converted to decimal, not octal.

print "mode (octal): "; Prompt for file mode.


chmod oct(<STDIN>), $file; RIGHT—mode string converted
to octal.

When a number is automatically converted to a string, or vice versa, both


representations remain. They will persist until the value of the variable is
changed.
Usually, it does not matter whether a variable contains a string or a
numeric value, but there are a few occasions when it does. For example,
the bitwise numeric operators act on the whole numeric value if applied to
a number, but characterwise if applied to a string:

2. Well, sort of. Perl prefers to use gconvert(). This is one of the reasons you
shouldn’t mess with $# any more.

from Effective Perl Programming, by Joseph N. Hall with Randal L. Schwartz


Understand conversions between strings and numbers. 21

$a = 123;
$b = 234;
$c = $a & $b; number 106

$a = "$a";
$b = "$b";
$d = $a & $b; string "020"

Finally, the error variable $! is an example of a variable with a “magic”


property. It returns the value of the system variable errno when it is used
in a numeric context, but it returns the string from the perror() function
(or some equivalent for your system) in a string context:

open ""; Invalid filename; should produce


an error.

print "$!\n"; "No such file or directory"

print 0 + $!, "\n"; "2" (or whatever)

http://www.effectiveperl.com
http://www.effectiveperl.com

You might also like