Reputation: 9600
I recently noticed that that re-initializing dynamic variables does not have the semantics I expected in most cases using assignment (binding works the way I expected it to, however).
Specifically, in this code:
sub g {
my $*i = CALLERS::<$*i> // 0;
my $*a1 = CALLERS::<$*a1> // Array.new;
my @*a2 = CALLERS::<@*a2> // Array.new;
$*i++;
$*a1.push: 'v1';
@*a2.push: 'v2';
dd $*i;
dd $*a1;
dd @*a2;
}
sub f {
my $*i = 0;
my $*a1 = Array.new;
my @*a2 = Array.new;
g; g; g;
}
f
I expected output of 3
, ["v1", "v1", "v1"]
, and ["v2", "v2", "v2"]
but instead get 1
, $["v1", "v1", "v1"]
, ["v2"]
. Switching to binding solves the issue, so there's no problem I'm trying to solve – but I would very much like to understand why assignment doesn't work here. I notice that a Scalar pointing to an Array works, but a Scalar pointing to an Int doesn't. But in either case, I would have thought that the newly assigned variable would receive the value from CALLERS. What am I missing about the semantics of assignment?
Upvotes: 8
Views: 142
Reputation: 26924
What am I missing about the semantics of assignment?
I think what you're missing, doesn't have anything to do with dynamic variables per se. I think what you're missing is the fact that:
my @a = Array.new;
is basically a noop. Because of the single argument rule, it is the same as:
my @a = ();
which is the same as:
my @a;
So, in your example in sub f
, the:
my @*a2 = Array.new;
in is just setting up an empty array in a dynamic variable.
Then in sub g
the:
my @*a2 = CALLERS::<@*a2> // Array.new;
is just basically doing (because of the single argument rule):
my @*a2;
and hence you don't see the push
es you've done before, because every call it starts out fresh.
Regarding the value of $*i
in sub g
: that also is just incrementing a copy of the callers $*i
, so the value remains at 1
in every call.
The reason that $*a1
works, is that containerization stops the flattening behaviour of the single argument rule. Observe the difference between:
sub a(+@a) { dd @a }; a [2,3,4]; # [2,3,4]
and:
sub a(+@a) { dd @a }; a $[2,3,4]; # [[2,3,4],]
Upvotes: 7