4

It appears as if a scalar by itself is sort of a list of one item:

> "foo"[1]
Index out of range. Is: 1, should be in 0..0
  in block <unit> at <unknown file> line 5

> "foo"[0]
foo
> "foo"[*-1]
foo

I say sort of a list of one because lists don't seem to have a range on their indexes:

> (0, 1, 2)[3]
Nil

What is going on here. What am I not understanding about the [] operator.

raiph
  • 31,607
  • 3
  • 62
  • 111
Chas. Owens
  • 64,182
  • 22
  • 135
  • 226
  • Shouldn't you rather look at (0, 1, 2)[2] as there is no third element of that list? – BarneySchmale Oct 10 '16 at 16:46
  • @BarneySchmale I am demonstrating the difference in the out of range behavior between the sort-of-list-of-one nature of scalars (dies) and actual lists (returns `Nil`), so no. – Chas. Owens Oct 11 '16 at 03:08
  • The `[]` operator is explained in depth [here](https://docs.perl6.org/language/subscripts.html). It is designed ti be very generic and reusable - what happens in case of non-existent elements, is up to the object you're indexing. – smls Oct 12 '16 at 22:27

2 Answers2

7

This is a feature of Any. From the docs:

Since Perl 6 intentionally confuses items and single-element lists, most methods in Any are also present on class List, and coerce to List or a list-like type.

If you look at the implementation, you'll see that there is no actual coercion necessary as Any provides AT-POS, and that's what fails for indices different from 0.

In contrast, the implementation of actual lists only fails in case of negative indices and returns Nil otherwise.

Semantically, this is not entirely insane as one way to think of Nil is as a quiet failure, but it is indeed an inconsistency. It might be by design, as the 'listiness' of items is just a convenience feature and not part of the interface proper and thus might be supposed to complain noisily if misused.

Note that Array gives a third behaviour by returning Any by default, which can be understood in the context of auto-vivification.

Christoph
  • 164,997
  • 36
  • 182
  • 240
  • Apparently, the thought process is that you can use the return from a function as a list and it just works (eg `"foo".elems` returns 1). It looks like a better error message is being mooted on the #perl6 IRC channel. – Chas. Owens Oct 10 '16 at 13:03
5

It appears as if a scalar by itself is sort of a list of one item

If you explicitly apply a list operation to a scalar it behaves as if it were a list containing one element which is that scalar value.

What am I not understanding about the [] operator.

Indexing operations on a list (any Positional data structure; a List is a list but a list may not be a List) are checked according to the list's "shape", a list of "Indexing ranges".

You can only explicitly declare the indexing ranges of an Array.

# Value treated as list    shape   Indexing range

'a scalar value'           (1)     0..0         
(0,1,2)                    (*)     0..Inf
my @a                      (*)     0..Inf
my @b[42]                  (42)    0..41

(I'm slightly surprised by Lists (eg (0,1,2)), which have immutable shape, being assigned a shape of (*). Why not (3) (in the case of a 3 element list) if this is both known and immutable? (Perhaps it isn't?))

raiph
  • 31,607
  • 3
  • 62
  • 111