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?
Dynamic variables compute their own values by executing statements and logical expressions. A dynamic variable assigns itself the result of a calculation or operation. The dynamic variable types are dynamic string, dynamic number, and dynamic True/False (Boolean).
Dynamic Variable Overview The distinguishing characteristic of a dynamic variable is that its value can change while the application runs. For example, your application might maintain a threshold value that is compared to a field value in each tuple processed.
A dynamic variable is a variable you can declare for a StreamBase module that can thereafter be referenced by name in expressions in operators and adapters in that module. In the declaration, you can link each dynamic variable to an input or output stream in the containing module.
Users can follow the below syntax to create the dynamic array to store dynamic variables. let array = []; for () { array[ key ] = value; // dynamically assign value to the key. }
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],]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With