A value held in a Scalar container is not automatically iterated
While both $s
and $seq
are scalars (aka "variables"), $s
is bound directly to a Seq value whereas your $seq
is bound to an intermediary Scalar (note uppercase S
) "container" that in turn contains the Seq. A value held in a Scalar container is not automatically iterated when used with features like for
.
In more detail:
my $s := 0 ... 3;
.say for $s;
Because the my
variable declaration uses the direct binding operator :=
for initialization, $s
is directly bound to the single Seq value 0 ... 3
.
This means the for
statement sees a single Seq value, determines that it does the Iterable role, and flattens (iterates) it.
Now consider this:
my $s := 0 ... 3;
my $container = $s;
.say for $container;
Because the second my
declaration uses the assignment operator =
for initialization, the new variable $container
is first bound to a new Scalar container which then "contains" whatever gets assigned.
In keeping with the language wide Slurpy Conventions (in particular: "An Iterable inside a Scalar container does not count"), a for
statement does not iterate a value held in a Scalar container, so the .say for $container
line only does one say
.
A similar situation applies for your original show
routine because variable parameter declarations are (semantically) containers by default.
One option is to instead add an is raw
trait to your $seq
parameter:
sub show ( $seq is raw ) { .say for $seq }
This prevents the usual automatic binding of $seq
to a Scalar container (that in turn would contain the Seq value) as part of the call to show
.
Another option is to let $seq
be bound to a Scalar container but explicitly flatten (iterate) the $seq
variable in the body of the show
routine using a prefix |
:
sub show ( $seq ) { .say for |$seq }