Raku list addition operator `Z+` 'fails' unless one of the lists is forced
my @foo = (1,1), (2,2);
say (3,3) Z+ @foo[*]; # (5 5)
say (3,3) Z+ @foo; # (5 5)
say (3,3) Z+ @foo<>; # (5 5)
say (3,3) Z+ @foo:v; # (5 5)
If you remove the
+ from the
Z, and you use
dd instead of
say, it may become clearer:
dd (3,3) Z @foo; # ((3, $(2, 2)),).Seq
So in this case, you get a list with
(2,2). Note the
$ before the
(2,2): that means it's itemized: to be considered a single item.
Z+, instead of creating a list, you're going to add the values.
When you write:
say 3 + (42,666); # 5
5 because you're adding the number of elements in the list to
3. That's why you're winding up with
5 in your example as well, not because the values in the list are
In the other cases the
Z operators sees non-itemized lists and so will iterate over its elements as you expected.
In case of doubt, make sure that you use
dd instead of
say in debugging: it will give you the nitty gritty of an expression, and not just a "gist" :-)
Another way of looking at things...
my @foo = (1,1), (2,2); say @foo.WHAT; # (Array) say @foo.WHAT; # (List) <== It was already a list, right?
==> No, it wasn't.
This is the primary key to your question in two respects:
First, as Liz notes, when trying to understand what's going on when you encounter a surprise, use
ddfocuses on the underlying reality.
Second, it's important to understand the role of
Scalars in Raku, and how that sharply distinguishes
Another way to see the underlying reality, and the role of
Scalars, is to expand your examples a little:
my @foo = (1,1), (2,2); say @foo.WHAT; # (Array) <== Top level elements "autovivify" as `Scalar`s say @foo.VAR.WHAT; # (Scalar) <== The element was a `Scalar`, not a `List` say @foo.WHAT; # (List) <== The `Scalar` returns the value it contains @foo = 42; # Works. <== The `Scalar` supports mutability my @foo2 is List = (1,1), (2,2); say @foo2.WHAT; # (List) <== `List` elements *don't* "autovivify" say @foo2.VAR.WHAT; # (List) <== `VAR` on a non-`Scalar` is a no op say @foo2.WHAT; # (List) <== This time `@foo2` IS a *`List`* @foo2 = ...; # Attempt to assign to `List` bound to `@foo2` fails @foo2 := ...; # Attempt to bind to `@foo2` element fails
I'll draw attention to several aspects of the above:
Scalargenerally keeps quiet about itself
Scalarreturns the value it contains in an r-value context, unless you explicitly seek it out with
Scalarcontainers can be read/write or readonly
Until I wrote this answer, I had not cleanly integrated this aspect into my understanding of Raku's use of
Scalars. Perhaps it's obvious to others but I feel it's worth mentioning here because the
Scalarindicated by the
.rakuis a readonly one -- you can't assign to it.
Array"autovivifies" (automatically creates and binds) a read/write
Scalarfor each of its elements
If a value is assigned to an indexed position (say
@foo) of a (non-native)
Array, then if that element does not currently
False), then a fresh read/write
Scalaris "autovivified" as the first step in processing the assignment.
Listnever autovivifies a
Scalarfor any of its elements
When a value is "assigned" (actually bound, even if the word "assigned" is used) to an indexed position in a
List, no autovivification ever occurs. A
Scalars, including read/write ones, but the only way that can happen is if an existing read/write
Scalaris "assigned" to an element (indexed position), eg
my @foo := (42, $ = 99); @foo = 100; say @foo; # (42 100).
And now we can understand your code that yields
my @foo = (1,1), (2,2); # `@foo` is bound to a fresh non-native `Array` say @foo.VAR.WHAT; # (Scalar) -- @foo is an autovivified `Scalar` say @foo; # (2,2) -- `say` shows value contained by `Scalar` say (3,3) Z+ @foo; # (5) --- because it's same as follows: say +$(2,2); # 2 -- number of elements in a two element list † say (3,3) Z+ 2; # (5) -- `Z` stops if either side exhausted
† We're applying a coercive numeric operation (
+) to a list (
Positional value), not to its elements. A list, coerced to a number, is its "length" (count of elements). (Certainly for a non-sparse one. I'm not sure about sparse ones.)