Common problems with slices

In the last tip we covered array and hash slices. These allow us to access
multiple elements from an array or a hash in a single statement, providing
a lot of power in a single statement.

It's also possible to use slices incorrectly. Many people make the
following mistake when first learning Perl:

print @array[3];

# or

@array[3] += 4;

Fortunately (as long as we're using warnings) Perl catches these
errors and tells us:

Scalar value @array[3] better written as $array[3]

This is because @array[3] is a slice of an array containing a single
element. In many cases this mistake won't cause us any problems,
but when problems do occur they can be very difficult to debug.

Consider the following code:

my @animals = qw(cat dog chicken duck rabbit);

my $pet = @animals[3];

When we use a slice in a scalar context, as we are doing above, the list
evaluates to the final value. Thus @animals[3] and $animals[3] both
return duck. Note that @animals[0..3] would also return duck.
This is one case where our mistake is unlikely to be a problem.

As discussed in the previous tip, we can assign lists of values to slices:

@animals[3,5,6] = qw( duckling swan mouse );

Slices on the left hand side of an expression always evaluate in a list
context. What do you suppose happens in the following expression?

@data[1] = <STDIN>; # Almost certainly a mistake

In this case all of the lines from STDIN are read in (because we're in a
list context) but only the very first is stored in $data[1]. All other
lines are discarded. Had we instead written:

$data[1] = <STDIN>;

only the next line of data would be read and it would be stored in
$data[1] which is the expected behaviour.

One final place where using slices instead of array look ups can surprise
you is with the indices themselves. When you look up an array element any
expression between the square brackets is interpreted in a scalar context.
In the following example, each of the array assignments would add f to
the next (5th) array position.

In this case, the expression between the square brackets is interpreted in
a list context. This would then be the equivalent of writing:

@array['a', 'b', 'c'. 'd', 'e'] = 'f';

Since these values are not numbers, Perl will coerce them to zero giving
us:

@array[0, 0, 0, 0, 0] = 'f';
Thus the letter C<f> will be assigned to the zeroth position rather than to
the 5th position!

To avoid these problems and other problems like these, make sure you use
warnings and also look very carefully at your array look ups. The rule
is simple, use $ when looking up a scalar value, and @ when looking
up a list of values.

Single element slices like @array[3] are almost always a mistake
particularly on the left-hand side of an assignment.