Previous Page
Next Page

5.9. Array Indices

Use negative indices when counting from the end of an array.

The last, second last, third last, nth last elements of an array can be accessed by counting backwards from the length of the array, like so:

    # Replace broken frames...
    $frames[@frames-1] = $active{top};         # Final frame
    $frames[@frames-2] = $active{prev};        # Penultimate frame
    $frames[@frames-3] = $active{backup};      # Prepenultimate frame

Alternatively, you can work backwards from the final index ($#array_name), like so:

    # Replace broken frames...
    $frames[$#frames  ] = $active{top};        # Final frame
    $frames[$#frames-1] = $active{prev};       # Penultimate frame
    $frames[$#frames-2] = $active{backup};     # Prepenultimate frame

However, Perl provides a much cleaner notation for accessing the terminal elements of an array. Whenever an array access is specified with a negative number, that number is taken as an ordinal position in the array, counting backwards from the last element.

The preceding assignments are much better written as:


    
# Replace broken frames...
$frames[-1] = $active{top};
# 1st-last frame (i.e., final frame)
$frames[-2] = $active{prev};
# 2nd-last frame
$frames[-3] = $active{backup};
# 3rd-last frame

Using negative indices is good practice, because the leading minus sign makes the index stand out as unusual, forcing the reader to think about what that index means and marking any "from the end" indices with an obvious prefix.

Equally importantly, the negative indices are unobscured by any repetition of the variable name within the square brackets. In the previous two versions, notice how similar the three indices are (in that all three start with either [@frames-... or [$#frames...). Each index differs by only around 20%: two characters out of nine or ten. In contrast, in the negative-index version, every index differs by 50%, making those differences much easier to detect visually.

Using negative indices consistently also increases the robustness of your code. Suppose @frames contains only two elements. If you wrote:

    $frames[@frames-1] = $active{top};         # Final frame
    $frames[@frames-2] = $active{prev};        # Penultimate frame
    $frames[@frames-3] = $active{backup};      # Prepenultimate frame

you'd be assigning values to $frames[1] (the last element), $frames[0] (the first element), and $frames[-1] (the last element again!) On the other hand, using -1, -2, and -3 as indices causes the interpreter to throw an exception when you try to assign to a nonexistent element:


    Modification of non-creatable array value attempted, subscript -3 at frames.pl line 33.

    Previous Page
    Next Page