Duplicates the nth element from the top of the operand stack, where n is counted from 0.

1. Description

The index operator removes a non-negative integer n from the operand stack, counts down to the nth element from the top (where the top is position 0), and pushes a copy of that element onto the stack.

This operator is particularly useful for accessing elements deep in the stack without disturbing the intervening elements. It’s essentially a generalized form of dup, where 0 index is equivalent to dup.

This is a Level 1 operator, available in all PostScript implementations.

2. Syntax

anyn ... any0 n index anyn ... any0 anyn

2.1. Stack Effect

Table 1. Before Execution
Position Content

Top

n (integer) - Index of element to duplicate (0-based from top)

Top-1

any0 - Top element (index 0)

Top-2

any1 - Second element (index 1)

…​

…​

Top-(n+1)

anyn - Element at index n

Table 2. After Execution
Position Content

Top

anyn - Copy of the element at index n

Top-1

any0 - Original top element

Top-2

any1 - Original second element

…​

…​

Top-(n+1)

anyn - Original element at index n

3. Parameters

n

Non-negative integer specifying which element to duplicate. 0 indicates the top element, 1 the second element, etc.

anyn …​ any0

At least n+1 elements must be present on the stack below the n operand.

4. Return Values

A copy of the element at position n from the top of the stack (before the n was removed).

5. Examples

5.1. Basic Usage

% Stack positions are 0-based from top
(a)(b)(c)(d) 0 index -> (a)(b)(c)(d)(d)  % Top element
(a)(b)(c)(d) 1 index -> (a)(b)(c)(d)(c)  % Second element
(a)(b)(c)(d) 2 index -> (a)(b)(c)(d)(b)  % Third element
(a)(b)(c)(d) 3 index -> (a)(b)(c)(d)(a)  % Fourth element

5.2. Equivalent to dup

% These are equivalent
42 dup              % Stack: 42 42
42 0 index          % Stack: 42 42

5.3. Accessing Buried Values

% Access value deep in stack
1 2 3 4 5           % Stack: 1 2 3 4 5
2 index             % Stack: 1 2 3 4 5 3
% Retrieved third element (3) without disturbing stack

5.4. Using in Calculations

% Calculate: (a + b) * a
% where a and b are already on stack
10 20               % Stack: 10 20 (a=10, b=20)
add                 % Stack: 30
10                  % Need original 'a' again - but it's gone!

% Better approach:
10 20               % Stack: 10 20
1 index             % Stack: 10 20 10 (duplicate a)
3 1 roll            % Stack: 10 10 20
add                 % Stack: 10 30
mul                 % Stack: 300

5.5. Preserving Stack State

% Access value without rearranging stack
/x 100 def
/y 200 def
/z 300 def

x y z               % Stack: 100 200 300
2 index             % Stack: 100 200 300 100
% Retrieved x without disturbing y and z

6. Advanced Examples

6.1. Implementing pick Operation

% Some PostScript dialects have 'pick' which is same as 'index'
/pick {             % ... n -> ... elem
    index
} def

1 2 3 4 5
2 pick              % Stack: 1 2 3 4 5 3

6.2. Safe Index with Bounds Check

% Index with safety check
/safeIndex {        % ... n -> ... elem (or error)
    dup count 1 sub gt {
        pop
        (Error: index out of bounds) print
        0
    } {
        index
    } ifelse
} def

1 2 3
5 safeIndex         % Prints error, returns 0

6.3. Copying Multiple Deep Elements

% Copy elements at specific indices
/multiIndex {       % ... idx1 idx2 idx3 ... idxn n -> ... elem1 elem2 ... elemn
    dup 1 sub -1 0 {
        % For each index
        1 add index
        exch
    } for
    pop
} def

10 20 30 40 50
3 1 0               % Indices to copy
3 multiIndex        % Copies elements at positions 0, 1, 3

6.4. Stack Inspection

% Print stack element at index n without modifying stack
/printAt {          % ... n -> ...
    dup count 1 sub le {
        index =
    } {
        pop (Index out of range) =
    } ifelse
} def

1 2 3 4 5
2 printAt           % Prints: 3
count =             % Prints: 5 (stack unchanged)

7. Edge Cases and Common Pitfalls

Using index with n greater than or equal to the stack depth causes a rangecheck error.

7.1. Index Out of Range

% BAD: Index too large
1 2 3
5 index             % ERROR: rangecheck
                    % Only 3 elements, can't access index 5

7.2. Negative Index

% BAD: Negative indices not allowed
1 2 3
-1 index            % ERROR: rangecheck

7.3. Stack Underflow

% BAD: Not enough elements
clear
0 index             % ERROR: stackunderflow
                    % Need at least 1 element plus the index

7.4. Off-by-One Errors

% CAUTION: Remember indexing is 0-based
(a)(b)(c)
2 index             % Returns (a), not (c)!
% Position 0 = (c), Position 1 = (b), Position 2 = (a)
Remember that stack positions are counted from 0, where 0 is the topmost element. The index operand itself is removed before counting, so you’re indexing into the stack as it was before calling index.

7.5. Composite Object Sharing

% Remember: index copies references, not values
[1 2 3]             % Stack: [1 2 3]
0 index             % Stack: [1 2 3] [1 2 3]
% Both array references share the same value
0 99 put            % Modifies both: [99 2 3] [99 2 3]
  • dup - Equivalent to 0 index

  • copy - Copy multiple top elements

  • roll - Rotate stack elements

  • exch - Exchange top two elements

  • count - Get stack depth for bounds checking

9. PostScript Level

Available in: PostScript Level 1 and higher

This is a fundamental operator available in all PostScript implementations.

10. Error Conditions

stackunderflow

The operand stack has fewer than n+2 elements (n+1 elements plus the n operand itself).

clear
1 2 3               % 3 elements
3 index             % ERROR: stackunderflow
                    % Need 4 elements for index 3
rangecheck

The value of n is negative, or n is greater than or equal to the number of elements on the stack (excluding n itself).

1 2 3
5 index             % ERROR: rangecheck (only 3 elements)
1 2 3
-1 index            % ERROR: rangecheck (negative)
typecheck

The top operand is not an integer.

1 2 3
(not a number) index    % ERROR: typecheck

11. Performance Considerations

The index operator has O(1) constant time complexity. It’s very fast regardless of the index value, as it doesn’t need to traverse the stack.

However, frequently using large index values may indicate poor stack management. Consider restructuring your code to keep frequently accessed values near the top of the stack.

12. Best Practices

  1. Use for deep access: index is ideal when you need an element buried in the stack

  2. Prefer dup for top element: Use dup rather than 0 index for clarity

  3. Check bounds: Use count to verify sufficient stack depth before large indices

  4. Document stack layout: When using index, clearly document which stack position contains what

  5. Consider roll instead: For repeated access to deep elements, roll might be more efficient

12.1. Clear Documentation

% Always document stack layout when using index
/drawLine {         % x1 y1 x2 y2 -> -
    % Stack: x1 y1 x2 y2
    3 index         % Stack: x1 y1 x2 y2 x1
    3 index         % Stack: x1 y1 x2 y2 x1 y1
    moveto
    lineto
    stroke
} def

% Or better yet, use named values:
/drawLine {         % x1 y1 x2 y2 -> -
    4 dict begin
        /y2 exch def /x2 exch def
        /y1 exch def /x1 exch def
        x1 y1 moveto
        x2 y2 lineto
        stroke
    end
} def

13. See Also


Back to top

Copyright © 2025 Ribose. PostScript is a trademark of Adobe. Distributed under the MIT License.