Using scalar variables to refer to an array inside an explicit generator - raku

I've written a code to calculate the Fibonacci series using array variables inside the explicit generator like this:
my #fib = [0],[1],-> #a, #b {[|#a Z+ |#b]} ... Inf;
say #fib[^6];
This works as expected. But when I use scalar variables inside the same code, it works too:
my #fib_v2 = [0],[1],-> $a, $b {[|$a Z+ |$b]} ... Inf;
say #fib_v2[^6];
Could they be called scalar variables pointing to the arrays? What are they called when they are used in this manner?
Note that I've browsed the online Raku documentation but it's hard to spot that particular information i.e. if arrays can be referred using scalar variables.

You should say that "the scalar variables are bound to the arrays". Because that is what happens. You could think of:
-> $a, $b { say $a; say $b }("foo", "bar")
as:
{ my $a := "foo"; my $b := "bar"; say $a; say $b }
So, when you bind an array to a scalar, it is still an Array object. And calling methods on it, will just work. It may just make reading the code more difficult.
Note this is different from assigning an array to a scalar.
raku -e 'my $a := [1,2,3]; .say for $a'
1
2
3
versus:
raku -e 'my $a = [1,2,3]; .say for $a'
[1 2 3]
The for iterating logic sees the container in $a and takes that as a sign to NOT iterate over it, even though it contains an Iterable.
Note that I've browsed the online Raku documentation but it's hard to spot that particular information i.e. if arrays can be referred using scalar variables.
It basically falls out of correctly grokking the relation between containers and binding. About 4 years ago, I wrote a blog post about it: https://opensource.com/article/18/8/containers-perl-6 Please pardon the archaic naming :-)

Related

Why are arrays passed as arguments mutable but scalars are not?

Got this:
#! /usr/bin/env raku
use v6;
multi blah (#arg) { #arg = 7; }
multi blah ($arg) { $arg = '3'; }
my #array = 1, 2, 3;
blah #array;
say #array;
my $string = 'onetwothree';
blah $string;
say $string;
Get this:
[7]
Cannot assign to a readonly variable or a value
in sub blah at ./chop.raku line 5
in block <unit> at ./chop.raku line 12
I found this behavior surprising, particularly the ability to change to the array outside of the scope of the function.
Can someone please explain why I can change an array argument passed to a function but not a scalar? And is there a way to make arrays read only when passed to a function? Is there any way to make a scalar passed to a function mutable?
Can someone please explain why I can change an array argument passed to a function but not a scalar?
Arguments passed to a function are read-only (by default; more on that below) and so generally can't be changed. The reason that you can modify the Array is that Arrays are, themselves, mutable (see the Lists, sequences, and arrays page in the docs for details). This means that, even though you can't change the Array itself, you can still change the values in the Array.
And is there a way to make arrays read only when passed to a function?
The List is Raku's immutable type for positional data (sort of; it's not deeply immutable, but that's beyond the scope here). If you pass a List into a function, the function won't be able to modify the contents of that list. For example, this code throws an error:
my #l is List = (1, 2, 3);
sub f(#var) { #var[1] = 42 }
f #l;
Is there any way to make a scalar passed to a function mutable?
There are two ways, depending on what sort of mutability you want: you can use either the is rw and is copy traits. For example, you might declare a function like so:
sub f($a is copy, $b is rw) {...}
That declaration allows &f to modify both $a and $b. But for $a, &f is modifying its own local copy and won't have any effect on the value its callers see for $a. With $b, however, &f is modifying shared state and any changes it makes to $b will be visible even outside the scope of &f.

Can I bind multiple variables at once?

The following line declares a variable and binds it to the number on the right-hand side.
my $a := 42;
The effect is that $a is not a Scalar, but an Int, as can be seen by
say $a.VAR.^name;
My question is, can I bind multiple variables in one declaration? This doesn't work:
my ($a, $b) := 17, 42;
because, as can be seen using say $a.VAR.^name, both $a and $b are Scalars now. (I think I understand why this happens, the question is whether there is a different approach that would bind both $a and $b to given Ints without creating Scalars.)
Furthermore, is there any difference between using := and = in this case?
You can use sigilless containers:
my (\a, \b) := 17,42;
say a.VAR.^name; # Int
Sigilless variables do not have an associated container

Sigilless variables, constants, bindings: when to choose what

So, from the documentation is almost clear what the three entities from the title are, but it is not very clear what their purpose is.
Constants are common in many languages. You don't want to write 3.14 all over your code and that's why you define a constant PI that, by the nature of the thing it represents, cannot be changed and that's why its value is constant in time.
Defining a variable bound to another entity with := is also almost clear but not really. If I bind a variable to 3.14, isn't it the same as defining a PI constant? Is $a := $b actually defining $a as an alias to $b or, as some other languages call it, a reference? Also, references are generally used in some languages to make it clear, in object construction or function calls, that you don't want to copy an object around, but why would it be useful, in the same scope, to have
$number_of_cakes = 4;
$also_the_number_of_cakes := $number_of_cakes;
?
Finally, the documentation explains how one can define a sigilless variable (that cannot be varied, so, actually, yet another kind of constant) but not why one would do that. What problems do sigilless variables solve? What's a practical scenario when a variable, a constant, a binding variable do not solve the problem that a sigilless variable solve?
Constants are common in many languages. You don't want to write 3.14 all over your code and that's why you define a constant PI that, by the nature of the thing it represents, cannot be changed and that's why its value is constant in time.
For that you use constant.
A constant is only initialized once, when first encountered during compilation, and never again, so its value remains constant throughout a program run. The compiler can rely on that. So can the reader -- provided they clearly understand what "value" means in this context.1
For example:
BEGIN my $bar = 42;
loop {
constant foo = $bar;
$bar++;
last if $++ > 4;
print foo; # 4242424242
}
Note that if you didn't have the BEGIN then the constant would be initialized and be stuck with a value of (Any).
I tend to leave off the sigil to somewhat reinforce the idea it's a constant but you can use a sigil if you prefer.
Defining a variable bound to another entity with := is also almost clear but not really. If I bind a variable to 3.14, isn't it the same as defining a PI constant? Is $a := $b actually defining $a as an alias to $b or, as some other languages call it, a reference?
Binding just binds the identifiers. If either changes, they both do:
my $a = 42;
my $b := $a;
$a++;
$b++;
say $a, $b; # 4444
Finally, the documentation explains how one can define a sigilless variable (that cannot be varied, so, actually, another kind of constant) but not why one would do that.
It can be varied if the thing bound is a variable. For example:
my $variable = 42; # puts the value 42 INTO $variable
my \variable = $variable; # binds variable to $variable
say ++variable; # 43
my \variable2 = 42; # binds variable2 to 42
say ++variable2; # Cannot resolve caller prefix:<++>(Int:D);
# ... candidates ... require mutable arguments
I personally prefer to slash sigils if an identifier is bound to an immutable basic scalar value (eg 42) or other entirely immutable value (eg a typical List) and use a sigil otherwise. YMMV.
What problems do sigilless variables solve? What's a practical scenario when a variable, a constant, a binding variable do not solve the problem that a sigilless variable solve?
Please add comments if what's already in my answer (or another; I see someone else has posted one) leaves you with remaining questions.
Foonotes
1 See my answer to JJ's SO about use of constant with composite containers.
That's not one but at 5 questions?
If I bind a variable to 3.14, isn't it the same as defining a PI constant?
Well, technically it would be except for the fact that 3.14 is a Rat, and pi (aka π) is a Num.
Is $a := $b actually defining $a as an alias to $b or, as some other languages call it, a reference?
It's an alias.
$number_of_cakes = 4; $also_the_number_of_cakes := $number_of_cakes;
There would be little point. However, sometimes it can be handy to alias something to an element in an array, or a key in a hash, to prevent repeated lookups:
my %foo;
my $bar := %foo<bar>;
++$bar for ^10;
What problems do sigilless variables solve?
Sigilless variables only solve a programming style issue, as far as I know. Some people, for whatever reason, prefer sigilless varriables. It makes it harder to interpolate, but others might find the extra curlies actually a good thing:
my answer := my $ = 42;
say "The answer is {answer}";
What's a practical scenario when a variable, a constant, a binding variable do not solve the problem that a sigilless variable solve?
In my view, sigilless variables do not solve a problem, but rather try to cater different programming styles. So I'm not sure what a correct answer to this question would be.
Also constant is our scoped by default.

Coercion/type checking: manually reproduce Perl6 standards

I have a Module AttrX::Mooish which implements some of attribute features of Moo/Moose frameworks (lazyness, trigger, etc.). I also wanted the module to be as transparent to the end user as possible meaning support for both private and public attributes. It works by replacing attribute's container with a Proxy and storing its value in external storage. It also means that all the type checking and coercion Perl6 was doing is now my responsibility. My target is to mimic the default behavior is much as possible. I.e. for the end user:
has MyClass #foo is mooish(...);
must work the same as it would without the trait applied. Unfortunately, the subject of type manipulations is so much complicated and ununified in the language core that the more problems I fix the more problems I get afterwards. For example:
my Str #a = <a b c>; my Str #b = [1,2,3]
Type check failed in assignment to #b; expected Str but got Int (1)
As expected.
my Str #a; say #a.WHAT
(Array[Str])
Sure.
my Array[Str] $a = ["a", "b", "c"];
Type check failed in assignment to $a; expected Array[Str] but got Array ($["a", "b", "c"])
Well....
my Array[Str] $a = <a b c>;
Type check failed in assignment to $a; expected Array[Str] but got List ($("a", "b", "c"))
Not even coercing List to Array!
No wonder that the final typecheck line in my trait code:
$coerced-value ~~ $attr.type
Fails here and there despite same values/types used in variable/attribute assignments work OK.
I have a question with no hope of getting any positive answer to it: is there a single entry point used by the assignment operator which does all the coerce/typecheck? Ideally I would simply:
$value = coerce($value, $type);
check-type($value, :type($attr.type), :name($attr.name))
I tried to trace down from the grammar, but haven't got enough spare time to complete this yet. Besides, it is mostly nqp which I don't know and can't really understand.
But since the existence of such entry point(s) is unlikely I would like to ask for any advises related to this area. Like, for example, SmokeMachine on #perl6 provided me with a great idea of obtaining base type of a parametrized type using .^parents method.
So far, the biggest problems are with:
To check if type is parametrized I can't use a single role or class to match against. So far the only approach I have is by finding if there is of method and testing its output. Unfortunately, if a class provides FALLBACK very unclear error message (the one about AUTOGEN) is produced. :no_fallback is desirable, but definite and subset types have their own find_method which doesn't support named parameters and I end up with another error message.
If a prepare type-related attributes ($!coerce-type) in compose method of my trait role applied to the Attribute object (where actually the attributes are declared) I find them later at run-time unitialized. Guessing its something related to compose time. But wanna be sure if nothing is missed here.
Is there any better way to perform type-check than $value ~~ $type?
[Comments indicate that this out-of-date question was supposed to be closed in 2020 but it never was. Here's a very brief answer in case someone comes across this.]
Sometime after asking this question, the asker significantly revised Raku's coercion mechanism. See Report on New Coercions. This new syntax for coercion is in the docs.
Using this new style, the following line from the question:
my Array[Str] $a = ["a", "b", "c"];
say $a;
# OUTPUT: Type check failed in assignment to $a;
# expected Array[Str] but got Array ($["a", "b", "c"])
becomes
my Array[Str]() $a = ["a", "b", "c"];
say $a;
# OUTPUT: [a b c]
(That is, Array[Str]() means "something that can be coerced into an Array of Strings". That's different from Array[Str()] ("an Array of things that can be coerced to Strings") and from Array[Str()]() ("something that can be coerced into an Array of things that can be coerced into Strings").)
Similarly, the following part of the question now has an answer:
is there a single entry point used by the assignment operator which does all the coerce/typecheck? Ideally I would simply [define how a type is coerced into my type]
With the new coercion protocol, the "single entry point" is the COERCE method, which users can define for their types to teach Raku how to coerce into those types.

"Cannot assign to immutable value" when trying to assign to a string + role

Starting with the example in the Iterable doc page
role DNA does Iterable {
method iterator(){ self.comb.iterator }
};
my #a does DNA = 'GAATCC';
.say for #a; # OUTPUT: «G␤A␤A␤T␤C␤C␤»
I found it weird it's declared using the #, so I changed it to the natural way of declaring strings, $:
my $a does DNA = 'GAATCC';
But that fails with a somewhat bewildering "Cannot assign to an immutable value". No need to assign on the spot, so we can do:
my $a = 'GAATCC';
$a does DNA;
.say for $a;
Which just leaves mixing-in for later. But that just prints the string, without paying any attention to the Iterable mixin. Let's call it then explicitly:
.say for $a.iterator;
it does kinda the same thing as before, only it prints the value of $a.iterator, without actually calling the function:
<anon|69>.new
This looks like the same thing it's going on in this other question. Baseline question is I don't understand what role Iterable really does, and what for really does and when it is calling iterator on some object. Any idea?
I don't think this line does what you think it does:
my #a does DNA = 'GAATCC';
It is the same as:
my #a := [ 'GAATCC', ];
#a does DNA;
Basically the .comb call coerces the array into a Str, and splits that into characters.
If you instead did this:
my #a = 'GAATCC' but DNA;
Which is basically the same as
my #a := Seq.new(('GAATCC' but DNA).iterator).Array;
Note that # variables store Positional values not Iterable values.
The thing you want is
my $a = 'GAATCC' but DNA;
$a.map: &say;
If you want to be able to use for you can't use a variable with a $ sigil
my \a = 'GAATCC' but DNA;
.say for a;
You may want to add Seq list List etc methods to DNA.
role DNA does Iterable {
method iterator(){
self.comb.iterator
}
method Seq(){
Seq.new: self.iterator
}
method list(){
# self.Seq.list
List.from-iterator: self.iterator
}
}
my $a = 'GAATCC' but DNA;
.say for #$a;
Your question's title points to a bug. This answer covers the bug and also other implicit and explicit questions you asked.
Background
fails with a somewhat bewildering "Cannot assign to an immutable value".
I think that's a bug. Let's start with some code that works:
my $a = 42;
say $a; # 42
say WHAT $a; # (Int) type of VALUE currently ASSIGNED to $a
say WHAT VAR $a; # (Scalar) type of VARIABLE currently BOUND to $a
$a = 42; # works fine
In the my declaraton $a gets BOUND to a new Scalar container. A Scalar container normally hides itself. If you ask WHAT type $a is, you actually get the type of the value currently ASSIGNED to the Scalar (the value it "contains"). You need VAR to access the container BOUND to $a. When you assign with = to a Scalar container you copy the assigned value into the container.
role foo {}
$a does foo; # changes the VALUE currently ASSIGNED to $a
# (NOT the VARIABLE that is BOUND to $a)
say $a; # 42 mixed in `foo` role is invisible
say WHAT $a; # (Int+{foo}) type of VALUE currently ASSIGNED to $a
say WHAT VAR $a; # (Scalar) type of VARIABLE currently BOUND to $a
$a = 99; say $a; # 99
The does mixes the foo role into the 42. You can still assign to $a because it's still bound to a Scalar.
Note how these two uses of does have very different effects:
my $a does foo; # mixes `foo` into VARIABLE bound to $a
$a does foo; # mixes `foo` into VALUE assigned to $a
The bug
$a.VAR does foo; # changes VARIABLE currently BOUND to $a (and it loses the 42)
say $a; # Scalar+{foo}.new VALUE currently ASSIGNED to $a
say WHAT $a; # (Scalar+{foo}) type of VALUE currently ASSIGNED to $a
say WHAT VAR $a; # (Scalar+{foo}) type of VARIABLE currently BOUND to $a
$a = 'uhoh'; # Cannot assign to an immutable value
The does mixes the foo role into the Scalar bound to $a. It seems that a Scalar with a mixin no longer successfully functions as a container and the assignment fails.
This currently looks to me like a bug.
my $b does foo; # BINDS mixed in VARIABLE to $b
$b = 'uhoh'; # Cannot assign to an immutable value
my $b does foo has the same result as my $b; $b.VAR does foo; so you get the same problem as above.
Other things you were confused about
my $a = 'GAATCC';
$a does DNA;
.say for $a;
just prints the string, without paying any attention to the Iterable mixin.
Because the $a VARIABLE is still bound to a Scalar (as explained in the Background section above), the VALUE that now has a DNA role mixed in is irrelevant per the decision process for uses about whether to call its argument's .iterator method.
Let's call it then explicitly ... prints the value of $a.iterator, without actually calling the function:
.say for $a.iterator;
Well it does call your DNA role's .iterator method. But that has another .iterator call at the end of the self.comb returned by your DNA role's iterator method so you're .saying that secondary .iterator.
Solutions that work today
I think Brad's answer nicely covers most of your options.
And I think your nice does DNA gist is as good as it gets with today's P6 if you want to use the $ sigil.
A solution that might one day work
In an ideal world all the sweetness in the P6 design would be fully realized in 6.c and the Rakudo compiler implementation of Perl 6. Perhaps that would include the ability to write this and get what you want:
class DNA is Scalar does Iterable { ... }
my $a is DNA = 'GAATCC';
.say for $a;
The ... code would be about the same as what you have in your gist except that the DNA class would be a scalar container, and so the new method would instead be a STORE method or similar that would assign the passed value to a $!value attribute or some such when a value was assigned to the container using =.
But instead, you get:
is trait on $-sigil variable not yet implemented. Sorry.
So the closest you can get today to the ideal of = 'string' to change $a is to bind using := DNA.new('string') as you did in your gist.
Note that you can bind arbitrary composite containers to # and % sigil variables. So you can see how things are supposed to eventually work.