With the routine definition below
sub bar( Int @stuff ) {
return [+] @stuff;
}
Both the lines below fail:
say bar( ^3 );
say bar( [1,2,3] );
with error
Type check failed in binding to parameter '@stuff';
expected Positional[Int] but got Array ($[1, 2, 3])
Assignment to a variable with the same definition, however, works
my Int @works = [1,2,3] ;
say bar( @works );
Obviously variable assignment and argument binding does not work in exactly the same way, but is it because type checking is strict?
Or Is there any other mechanism at work?
Assignment is a copying operation. When we say:
my @a = @b;
Then it:
@b
@a
Which is why future assignments into @b
(or push
es, or pop
s, etc.) will not affect @a
. (As an aside, it also means that my @a = [1,2,3]
is rather wasteful, because it constructs an anonymous Array
, only to iterate it and then leave it for GC immediately afterwards.)
When we have:
my @a = 1, 2, 3;
my Int @b = @a;
Then the type-checking is performed on each assignment into a slot of @b
. It's the values that matter. Of course, we have to do O(n) type checks, but the semantics of =
mean we're doing an O(n) operation anyway.
By contrast, binding is an aliasing operation. It makes a symbol reference a value. It is O(1) operation. If we have:
my @a = 1, 2, 3;
my Int @b := @a;
Then it must fail, because @a
is not appropriately constrained. We can't just go through @a
and check its values are Int
; for one, it'd change the complexity of the operation, making the performance of the code hard to reason about, but also, @a
could later have, for example, 1.5
assigned in to it, rendering the type constraint on @b
meaningless, since it aliases the same thing.
Parameter passing works through binding, thus the effect observed in the question.
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