Subscript and slice operators#

The bracket-and-brace family that picks elements out of arrays and hashes — and the deref-brace family that does the same through a reference.

Form

Selects

Container

Result type

$arr[i]

one element

array

scalar

$hash{key}

one element

hash

scalar

@arr[i, j, k]

many elements (slice)

array

list

@hash{k1, k2}

many elements (slice)

hash

list

%arr[i, j, k]

key/value slice

array

list (k,v…)

%hash{k1, k2}

key/value slice

hash

list (k,v…)

A few rules cover all twelve combinations.

The sigil signals the result, not the container#

@arr is the array; $arr[3] is one of its elements. The leading sigil tells you what kind of value you are accessing — scalar ($), list of values (@), key/value list (%):

my @arr = (10, 20, 30, 40, 50);

$arr[2]           # 30                — scalar (single element)
@arr[1, 3]        # (20, 40)          — list of values at those indices
%arr[1, 3]        # (1 => 20, 3 => 40) — list of (index, value) pairs
my %h = (a => 1, b => 2, c => 3);

$h{a}             # 1                 — scalar
@h{'a', 'c'}      # (1, 3)            — list of values
%h{'a', 'c'}      # (a => 1, c => 3)  — list of (key, value) pairs

The ”%-slice“ forms (%arr[...], %hash{...}) are a Perl 5.20 addition that returns key/value pairs as a list. They are the right tool when you want a copy of part of a hash:

my %selected = %h{ qw(a c) };           # %selected = (a => 1, c => 3)

Negative indices on arrays#

Negative array indices count from the end:

$arr[-1]          # last element
$arr[-2]          # second-from-last
@arr[-3..-1]      # last three elements as a slice

Out-of-range positive indices read as undef. Out-of-range negative indices (further back than the start) raise a fatal runtime error:

my @a = (1, 2, 3);
$a[10]            # undef (with no warning)
$a[-10]           # FATAL: Modification of non-creatable array value
                  # (the error wording reflects how the lookup is implemented)

Slice as lvalue#

Both array and hash slices are valid assignment targets:

@arr[0, 2, 4] = ('A', 'C', 'E');         # set positions 0, 2, 4
@h{qw(a b c)} = (1, 2, 3);               # set three hash keys

(@arr[0, 1], @arr[1, 0]) = ...            # be careful: aliasing!

You can swap elements via slice assignment without a temporary:

@arr[$i, $j] = @arr[$j, $i];             # swap two array elements
@h{$key1, $key2} = @h{$key2, $key1};     # swap two hash values

Hash key autoquoting#

Inside {} for hash subscripts, bareword identifiers are auto-quoted:

$h{name}          # same as $h{'name'}
$h{first_name}    # same as $h{'first_name'}
$h{1_2}           # FATAL — not a valid bareword identifier
$h{"1_2"}         # quote it explicitly

This is one of the most-loved (and most-bug-causing) Perl conveniences. The bareword-or-not decision happens at parse time based on the literal token; constants and computed values do not benefit:

use constant KEY => 'name';
$h{KEY}           # WRONG — this is the bareword "KEY", not the constant!
$h{KEY()}         # use empty parens to force function-call evaluation
$h{+KEY}          # or unary +, the canonical workaround

The +KEY form is the most compact way to say ”this is not a bareword, evaluate it as an expression“.

Array indices: integer-coerced, no autoquoting#

[] indices are evaluated as expressions and coerced to integers (truncating toward zero):

$arr[1.7]         # $arr[1]    — 1.7 truncates to 1
$arr["3"]         # $arr[3]    — string coerces to integer
$arr[$#arr]       # last element  ($#arr is last valid index)

The $#arr syntax inside subscripts is idiomatic for ”last“:

$arr[$#arr]       # last
@arr[0..$#arr]    # all of @arr (verbose; just write @arr)
@arr[1..$#arr]    # all except first

Mixing — multidimensional access#

Perl 5 does not have native multi-dimensional arrays; nested data is built from references:

my @grid = ([1,2,3], [4,5,6], [7,8,9]);

$grid[1][2]       # 6                  — chained subscripts on AoA
$grid[1]->[2]     # same — the arrow is optional between subscripts
$grid[$y][$x]

The arrow-between-subscripts is implied by Perl’s grammar: when two subscripts immediately follow each other on a deref chain, the -> can be omitted. See arrow.

See also#

  • Arrow->[] and ->{} for going through a reference; the arrow-elision rule.

  • Assignment — slice assignment; multi-target destructuring.

  • exists, delete — perlfunc forms that take a subscript expression.

  • keys, values — whole-container forms; the slice operators are the partial forms.

  • Arrays, Hashes — the data-types pages explain the sigil-vs-result rule that governs which subscript form to use.