As with my previous question, this is an area where I can't tell if I've encountered a bug or a hole in my understanding of Raku's semantics. Last time it turned out to be a bug, but doubt lightning will strike twice!
In general, I know that I can pass named arguments to a function either with syntax that looks a lot like creating a Pair (e.g. f :a(42)
) or with syntax that looks a lot like flattening a Hash (e.g., f |%h
). (see argument destructuring in the docs). Typically, these two are equivalent, even for non-Scalar parameters:
sub f(:@a) { dd @a }
my %h = a => [4, 2];
f :a([4,2]); # OUTPUT: «Array element = [4, 2]»
f |%h; # OUTPUT: «Array element = [4, 2]»
However, when constructing an object with the default .new
constructor, these two forms seem to give different results:
class C { has @.a; }
my %h = a => [4, 2];
C.new: :a([4,2]; # OUTPUT: «C.new(a => ([[4, 2]])»
C.new: |%h; # OUTPUT: «C.new(a => [[4, 2],])»
That is, passing :a([4,2])
results in a two-element Array, but using the argument-flattening syntax results in a one-element Array containing a two-element Array.
Is this behavior intended? If so, why? And is there syntax I can use to pass |%h
in and get the two-element Array bound to an @
-sigiled attribute? (I know using an $
-sigiled attribute works, but I prefer the semantics of the @
).
Is this behavior intended?
Yes. Parameter binding uses binding semantics, while attribute initialization uses assignment semantics. Assignment into an array respects Scalar
containers, and the values of a Hash
are Scalar
containers.
If so, why?
The intuition is:
is copy
on a parameter to get assignment semantics).And is there syntax I can use to pass |%h in and get the two-element Array bound to an @-sigiled attribute?
Coerce it into a Map
:
class C { has @.a; }
my %h = a => [4, 2];
say C.new: |%h.Map;
Or start out with a Map
in the first place:
class C { has @.a; }
my %h is Map = a => [4, 2];
say C.new: |%h;
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