Positional subscript Written
Indexing and slicing by position — one operator that returns an element, a list, or the whole thing depending on what you put inside it.
[ ]- R1One index returns one element
- R2More than one index returns a list — a slice
- R3The subscript is evaluated in list context, so anything list-like indexes
- R4
*inside a subscript means "the number of elements" - R5An empty subscript is the whole thing — the zen slice
- R6Reading past the end returns
Anyand does not grow the array - R7Assigning past the end does grow the array, filling with
Any - R8A slice is assignable
- R9Adverbs select what the subscript returns
- R10Booleans index, because
Boolis anInt - R11Subscripting a scalar item yields the item itself at index 0
- T1Negative indices are not "from the end"
- T2A single list subscript flattens; a list inside the subscript does not
- T3
;inside a subscript is the multi-dimensional form, and Raku++ differs on flat arrays - T4Binding a slice gives different types in the two implementations
@a[…] looks up by position. What comes back depends entirely on the shape of what is inside the brackets, and the bracket contents are ordinary Raku code evaluated in list context — not a special index syntax.
This is postcircumfix:<[ ]>, distinct from [circumfix:<[ ]>](/rules/operators/circumfix-brackets/), which builds an array. The difference is whether a term precedes the bracket.
Rules #
R1 One index returns one element
my @a = 10, 20, 30; say @a[1];
20R2 More than one index returns a list — a slice
The result is a List, in the order you asked for, repeats included. It is not a copy of a range of the array; it is the elements you named.
my @a = 10, 20, 30; say @a[0, 2]; say @a[1, 1, 0];
(10 30)
(20 20 10)R3 The subscript is evaluated in list context, so anything list-like indexes
A range, a sequence, a ^n, the result of a method call — all of them flatten into the index list. There is no separate "slice syntax"; there is only list context.
my @a = 1 .. 10; say @a[2 .. 4]; say @a[^3]; say @a[(1, 2).map(* * 2)];
(3 4 5)
(1 2 3)
(3 5)R4 * inside a subscript means "the number of elements"
*-1 is not a negative index — it is a WhateverCode closure that the subscript calls with the element count. That is why it composes with arithmetic.
my @a = 10, 20, 30; say @a[*-1]; say @a[*-1, *-2];
30
(30 20)R5 An empty subscript is the whole thing — the zen slice
@a[] returns the container itself, not a copy and not a flattened list. It is how you ask for "everything" without changing the shape.
my @a = 10, 20, 30; say @a[];
[10 20 30]R6 Reading past the end returns Any and does not grow the array
my @a; say @a[3].WHAT; say @a.elems;
(Any)
0R7 Assigning past the end does grow the array, filling with Any
The asymmetry is deliberate: reading is free, writing commits.
my @a; @a[3] = 1; say @a.raku;
[Any, Any, Any, 1]R8 A slice is assignable
my @a = 1, 2, 3; @a[0, 1] = 9, 8; say @a;
[9 8 3]R9 Adverbs select what the subscript returns
The subscript takes adverbs that change the result from the value to something about the value: :exists, :delete, :k (keys), :v (values), :p (pairs).
my @a = <a b c>; say @a[2]:exists; say @a[9]:exists; say @a[0, 1]:kv;
True
False
(0 a 1 b):delete returns what was there and leaves a hole, not a shorter array:
my @a = <a b c>; say @a[1]:delete; say @a.raku;
b
["a", Any, "c"]R10 Booleans index, because Bool is an Int
True is 1 and False is 0, so a boolean subscript is a perfectly ordinary numeric one. Occasionally useful, more often a bug.
my @a = 10, 20, 30; say @a[True, False];
(20 10)R11 Subscripting a scalar item yields the item itself at index 0
Any value is a one-element list when asked. This is why %h[0] gives you the hash rather than an error, and why $s[0] is the whole string rather than its first character.
my $s = "abc"; say $s[0]; my %h = a => 1; say %h[0];
abc
{a => 1}For a character, index the .comb list — $s.comb[0] — or use .substr(0, 1).
Traps #
T1 Negative indices are not "from the end"
@a[-1] is an error, not the last element. Raku spells that @a[*-1]. Rakudo rejects it at compile time with a message pointing you at *-1; Raku++ accepts the parse and throws X::OutOfRange when the subscript runs. Either way the code is wrong — but the two implementations tell you at different moments.
my @a = 1, 2, 3;
say @a[-1];
T2 A single list subscript flattens; a list inside the subscript does not
One list in the brackets is just an index list:
my @a = 10, 20, 30; say @a[(0, 1)];
(10 20)But a list nested among other indices is a different matter, and this is where the two implementations part company. Rakudo mirrors the shape of the subscript into the result, so @a[0, (1, 2)] returns a two-element list whose second element is itself a list:
my @a = 10, 20, 30;
say @a[0, (1, 2)];Rakudo: (10 (20 30))
Raku++: (10 20 30)
Raku++ flattens. If the shape matters, do not rely on the subscript to preserve it — build it explicitly. To index into a nested array, chain the subscripts (@a[0][1]) or use the semicolon form below.
T3 ; inside a subscript is the multi-dimensional form, and Raku++ differs on flat arrays
@a[0;1] indexes dimension by dimension. On a genuinely nested array both implementations agree:
my @a = [1, 2], [3, 4]; say @a[0; 1];
2On a flat array, Rakudo lets a trailing dimension degenerate — @a[1;0] gives @a[1] — while Raku++ returns Any. Treat ; on a one-dimensional array as undefined territory rather than relying on either answer.
my @a = 1, 2, 3;
say @a[1; 0];T4 Binding a slice gives different types in the two implementations
my @b := @a[0, 1] binds a List in Rakudo and an Array in Raku++. The values match; .WHAT and mutability do not. Assign (=) instead of bind (:=) unless you specifically need the binding.
my @a = 1, 2, 3;
my @b := @a[0, 1];
say @b.^name;See also #
- [
circumfix:<[ ]>](/rules/operators/circumfix-brackets/) — the same brackets with no preceding term: an array composer postcircumfix:<{ }>— the associative subscriptprefix:<[>— the reduction metaoperator,[+] @a