For instance, in this case:
my @list = (2,) but "bar";
put @list.Str «2»
There does not seem to be a way to access the "bar" component. Am I missing something? Same will happen, for instance, with Set
my @list = (2,3) but Set(4,5);
put @list.Set; # OUTPUT: «3 2»
Assignment is a copying operation, so:
my @a = something;
Creates an Array
in @a
, iterates something
, and stores each element in @a
. If binding is used instead:
my @list := (2,) but "bar";
put @list.Str;
Then the list with the mixin is bound to the symbol @list
, and the output is:
bar
TL;DR I think I'm now closer to understanding what you meant. I share various solutions based on that understanding at the start of this answer. (The rest of this answer is perhaps now mostly moot, but I've left it in because I think it still has some value, especially the apparent bug which still baffles me.)
role foo { method Str { 42 } }
...
say @bar.Str; # 42
where the ...
is suitably filled in, eg one of:
class List2 is List does foo {}
my @bar is List2;
What this does, and when:
Creates a new container type List2
composing List
with role foo
.
Permanently "binds" the variable @bar
to a new instance of the new container type.
All of this happens at compile-time.
my @bar is List;
@bar does foo;
What this does, and when:
Permanently "binds" the variable @bar
to a new instance of List
at compile-time.
Permanently mixes foo
into the same List
instance at run-time.
my @bar := (1,2) but foo
What this does, and when:
Constructs a new List
instance at compile-time from the literal ((1,2)
).
Constructs a new instance at run-time that's a clone of the List
constructed from the list literal but with the foo
role mixed in.
Temporarily "binds" the variable @bar
to the new List
/ foo
object ((1,2) but foo
).
The code you shared, and its behaviour, is mostly basic ordinary behaviour. jnthn's answer explains these basic aspects. This answer provides a bit more detail and notes one part that surprised me and might be a bug.
Is there a way to access mixed-in components when the original variable has a default coercion?
I think I see something unexpected going on that might be what you're talking about. But I wouldn't describe it as "default coercion" given that both "default" and "coercion" already have specific meanings in Raku, and it's not to do with those. Modulo the strange behaviour it's just Raku's ordinary semantics for assigning a plural value to a plural variable.
For instance, in this case:
my @list = (2,) but "bar";
jnthn's answer explains why that's not going to work. In a nutshell the mixin is on the plural value, not on each of the elements within that plural value, so it won't get copied as part of the assignment. Your code is "broken" before you start.
You could reasonably write something like this and expect it to work:
my @list = (2,) Zbut "bar";
put @list.Str; # «bar»
The Z
in the first line distributes the but
over the singular elements in the plural List
value using zip semantics. There's only one element -- 2
-- but it also works if there are more:
my @list = 2,3 Zbut "bar", "foo";
put @list.Str; # «bar foo»
It's useful to be clear about what's happening in that second line.
The .Str
method is being called on a plural value (an Array
that gets implicitly created and bound to @list
as part of declaring my @list
).
As with most programming languages, each routine in Raku gets to decide what it's going to do based primarily on its arguments. And like most PLs with methods, methods can do perhaps surprisingly different things depending on their invocant.
In Raku the .Str
method, when called with a plural value/variable invocant distributes a .Str
to each element in that plural invocant. (And if any of its elements is itself another plural that call will recursively do the same to its elements.) When all is done, the series of resulting individual strings are concatenated with a space between each.
Same will happen, for instance, with
Set
As before, you would again need to distribute the mixin to the individual elements in the first line to have any chance of things working out:
my @list = (2,3) Zbut Set(4,5);
But now the second line still won't do what you're expecting:
put @list.Set; # OUTPUT: «3 2»
The issue is that this time you're dealing with .Set
.
Calling .Set
on a plural is not like calling .Str
on a plural. It has completely different semantics. What it does is construct a set from the plural value's collection of elements. Thus:
say (1,2,3).Set; # Set(1 2 3)
Hopefully this has all made sense thus far.
Here's where we arrive at what has surprised me. This seems to work:
my @list = 2 but Set(4,5);
put @list[0].^name; # OUTPUT: «Int+{<anon|1>}»
put @list[0].Set; # OUTPUT: «4 5»
put @list[0].Set.^name; # OUTPUT: «Set»
But if we change the first line, things don't work as I would expect:
my @list = (2,3) Zbut Set(4,5);
put @list[0].^name; # OUTPUT: «Int+{<anon|1>}»
put @list[0].Set; # OUTPUT: «2»
put @list[0].Set.^name; # OUTPUT: «Set»
That's baffling me. I will sleep on it. But right now that seems like it might be a bug.
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