Item 2: Avoid using a slice when you want an element.
Is @a 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 something different, called a slice. A slice is a shortcut way of writing a list of elements:
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 is as much a slice as are @a[1, 2] , @a[2, 10] , @a[5, 3, 1] , @a[3..7] , and so on. @a 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 . The single-element slice @giant is still OK, sort of, since @giant in a scalar context evaluates to its last (and in this case only) element, $giant .
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.
This reads all the lines from standard input, assigns the first one to element of @info , and ignores the rest! Assigning <STDIN> to @info 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:
Don't confuse slices and elements.
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 as there are lines.
The contents of the lines are interpreted as integer indicesif 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 overwrite 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 in your programs. 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 command 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:
However, slices can be put to some pretty interesting (and weird) uses. For example:
They make a handy way to swap two elements:
Slices are also used in sorting (see Item 14):
Use slices to reorder arrays.
You can use hash slices to create hashes from two lists, to overlay the contents of one hash onto another, and to "subtract" one hash from another:
Use slices to create and manipulate hashes.