Is there a way to detect whether something is immutable? - raku

In Raku a scalar might be immutable or it might be an actual variable:
my $a := 6; # constant
my $b = 6; # variable
Is there a programmatic way to check whether a scalar is immutable without just trying to change it and seeing if it works?

First, a slight terminological correction (not to be nitpicky, but just because this area is a bit tricky and being precise with our terms can help).
It's not really right to say that my $a := 6 is a constant; that expression binds $a to the value 6, which prevents you from assigning a different value to $a (with the = operator). However, you can still rebind a new value to $a (with the := operator). This means that $a can still, in a sense, be mutated – or, at least, can be made to point to something new. For a truly constant $a, you should use either constant $a or change $a to a sigil-less variable (my \a = 6).
Now to the actual answer to your question: To determine whether $a is bound or assigned to a value, you can use $a.VAR.WHAT. If $a is assigned a value, this will return the type of container, (Scalar); if it is bound, then it will return the type of the bound value.
As far as I know, there isn't a way to tell the difference between an $a bound to a value and one that's a constant, though I would love to be wrong about that.
The code below illustrates what I just said:
my $a = 1;
say $a.VAR.WHAT; # OUTPUT: «(Scalar)»
$a = 2;
say $a; # OUTPUT: «2»
my $b := 1;
say $b.VAR.WHAT;# OUTPUT: «(Int)»
$b := 2;
say $b; # OUTPUT: «2»
constant $c = 1;
say $c.VAR.WHAT; # OUTPUT: «(Int)»
# $c := 2; ILLEGAL
say $c; # OUTPUT: «1»

Another way, using multiple dispatch:
my $a := 6; # constant
my $b = 6; # variable
multi sub mutable($ is rw) { True }
multi sub mutable($) { False }
say mutable($a); # False
say mutable($b); # True
say mutable(42); # False

Related

Assignment destructuring and operator precedence

The documentation says that the comma operator has higher precedence than the assignment = operator, and this is specifically different than in Perl, so that we are allowed to remove parentheses in some contexts.
This allows us to do things like this:
my #array = 1, 2, 3;
What I don't understand is why when do something like this:
sub test() { return 1, 2 }
my ($a, $b);
$a, $b = test();
$b get assigned [1 2] while $a gets no value.
While I would assume that the following would be equivalent, because the comma operator is tighter than the assignment.
($a, $b) = test();
The semantics of Raku have a lot of subtlety and I guess I am thinking too much in terms of Perl.
Like raiph said in the comments, my original assumption that the comma operator has higher precedence than the assignment operator was false. And it was due to a problem in the rendering of the operator precedence table, which didn't presented operators in their precedence order.
This explains the actual behavior of Raku for my examples.
The = operator itself is always item assignment level, which is tighter than comma. However, it may apply a "sub-precedence", which is how it is compared to any further infixes in the expression that follow it. The term that was parsed prior to the = is considered, and:
In the case that the assignment is to a Scalar variable, then the = operator works just like any other item assignment precedence operator, which is tighter than the precedence of ,
In any other case, its precedence relative to following infixes is list prefix, which is looser than the precedence of ,
To consider some cases (first, where it doesn't impact anything):
$foo = 42; # $ sigil, so item assignment precedence after
#foo = 1; # # sigil, so list assignment precedence after
#foo[0] = 1; # postcircumfix (indexing operator) means list assignment after...
$foo[0] = 1; # ...always, even in this case
If we have a single variable on the left and a list on the right, then:
#foo = 1, 2; # List assignment into #foo two values
$foo = 1, 2; # Assignment of 1 into $foo, 2 is dead code
These apply with the = initializer (following a my $var declaration). This means that:
loop (my $i = 0, my $j = $end; $i < $end; $i++, $j--) {
...
}
Will result in $i being assigned 0 and $j being assigned $end.
Effectively, the rule means we get to have parentheses-free initialization of array and hash variables, while still having lists of scalar initializations work out as in the loop case.
Turning to the examples in the question. First, this:
($a, $b) = test();
Parses a single term, then encounters the =. The precedence when comparing any following infixes would be list prefix (looser than ,). However, there are no more infixes here, so it doesn't really matter.
In this case:
sub test() { return 1, 2 }
my ($a, $b);
$a, $b = test();
The precedence parser sees the , infix, followed by the = infix. The = infix in itself is tighter than comma (item assignment precedence); the sub-precedence is only visible to infixes parsed after the = (and there are none here).
Note that were it not this way, and the precedence shift applied to the expression as a whole, then:
loop (my $i = 0, my #lagged = Nil, |#values; $i < #values; $i++) {
...
}
Would end up grouped not as (my $i = 0), (my #lagged = Nil, |#values), but rather (my $i = 0, my #lagged) = Nil, |#values, which is rather less useful.

IIFE alternatives in Raku

In Ruby I can group together some lines of code like so with a begin block:
x = begin
puts "Hi!"
a = 2
b = 3
a + b
end
puts x # 5
it's immediately evaluated and its value is the last value of the block (a + b here) (Javascripters do a similar thing with IIFEs)
What are the ways to do this in Raku? Is there anything smoother than:
my $x = ({
say "Hi!";
my $a = 2;
my $b = 3;
$a + $b;
})();
say $x; # 5
Insert a do in front of the block. This tells Raku to:
Immediately do whatever follows the do on its right hand side;
Return the value to the do's left hand side:
my $x = do {
put "Hi!";
my $a = 2;
my $b = 3;
$a + $b;
}
That said, one rarely needs to use do.
Instead, there are many other IIFE forms in Raku that just work naturally without fuss. I'll mention just two because they're used extensively in Raku code:
with whatever { .foo } else { .bar }
You might think I'm being silly, but those are two IIFEs. They form lexical scopes, have parameter lists, bind from arguments, the works. Loads of Raku constructs work like that.
In the above case where I haven't written an explicit parameter list, this isn't obvious. The fact that .foo is called on whatever if whatever is defined, and .bar is called on it if it isn't, is both implicit and due to the particular IIFE calling behavior of with.
See also if, while, given, and many, many more.
What's going on becomes more obvious if you introduce an explicit parameter list with ->:
for whatever -> $a, $b { say $a + $b }
That iterates whatever, binding two consecutive elements from it to $a and $b, until whatever is empty. If it has an odd number of elements, one might write:
for whatever -> $a, $b? { say $a + $b }
And so on.
Bottom line: a huge number of occurrences of {...} in Raku are IIFEs, even if they don't look like it. But if they're immediately after an =, Raku defaults to assuming you want to assign the lambda rather than immediately executing it, so you need to insert a do in that particular case.
Welcome to Raku!
my $x = BEGIN {
say "Hi!";
my $a = 2;
my $b = 3;
$a + $b;
}
I guess the common ancestry of Raku and Ruby shows :-)
Also note that to create a constant, you can also use constant:
my constant $x = do {
say "Hi!";
my $a = 2;
my $b = 3;
$a + $b;
}
If you can have a single statement, you can leave off the braces:
my $x = BEGIN 2 + 3;
or:
my constant $x = 2 + 3;
Regarding blocks: if they are in sink context (similar to "void" context in some languages), then they will execute just like that:
{
say "Executing block";
}
No need to explicitely call it: it will be called for you :-)

Unbind or undefine a variable in raku

After reading the Raku documentation, I only found this for undefining a variable. I believe that in Raku there are differences between assignment and binding.
Defining and undefining a scalar is easy.
> my $n
(Any)
> $n.defined
False
> $n = 3
3
> $n.defined
True
> $n = Nil
(Any)
> $n.defined
False
When the variable is binded, it's not possible.
> my $k := 5
5
> $k := Nil
===SORRY!=== Error while compiling:
Cannot use bind operator with this left-hand side
at line 2
------> <BOL>⏏<EOL>
> $k = Nil
Cannot assign to an immutable value
in block <unit> at <unknown file> line 1
For arrays or hashes, I can empty it, but the variable is still defined.
For functions, when you define a function with sub, you cannot undefine it, but you can with an anonymous function.
> my &pera = -> $n { $n + 2}
-> $n { #`(Block|140640519305672) ... }
> &pera = Nil
(Callable)
> &pera.defined
False
> my &pera = -> $n { $n + 2}
-> $n { #`(Block|140640519305672) ... }
> &pera = Nil
(Callable)
> &pera.defined
False
> sub foo ($n) { $n + 1}
&foo
> &foo.defined
True
> &foo = Nil
Cannot modify an immutable Sub (&foo)
in block <unit> at <unknown file> line 1
So what's the difference between assignment and binding?
How can I undefine a variable?
Lots of different issues to discuss here.
> my $k := 5;
> $k := Nil;
Cannot use bind operator
This first problem is the Raku REPL. cf your last SO. Have you tried CommaIDE or repl.it?
Your code is perfectly valid:
my $k := 5;
$k := Nil;
say $k; # Nil
Moving on:
my $k := 5;
$k = Nil;
Cannot assign to an immutable value
This is different. After binding 5 to $k, the $k = Nil code is attempting to assign a value into a number. Only containers[1] support assignment. A number isn't a container, so you can't assign into it.
Clarifying some cases you mentioned but didn't explicitly cover:
my #foo;
#foo := Nil;
Type check failed in binding; expected Positional...
While scalar variables (ones with a $ sigil) will bind to any value or container, an # sigil'd variable will only bind to a Positional container such as an Array. (Likewise a % to an Associative such as a Hash.)
Not only that, but these containers are always defined. So they still return True for .defined even if they're empty:
my #foo := Array.new; # An empty array
say #foo.elems; # 0 -- zero elements
say #foo.defined; # True -- despite array being empty
Now assigning Nil to an array:
my #foo;
#foo = Nil;
say #foo; # [(Any)]
If a declaration of an # sigil'd variable doesn't bind it to some explicit Positional type it is instead bound to the default choice for an # variable. Which is an Array with a default element value of Any.
The #foo = Nil; statement above assigns a Nil value into the first element of #foo. The assignment of a value into a non-existing element of a multi-element container means a new Scalar container pops into existence and is bound to that missing element before assignment continues. And then, because we're assigning a Nil, and because a Nil denotes an absence of a value, the Array's default value ((Any)) is copied into the Scalar instead of the Nil.
On to the sub case...
sub foo {}
&foo = {} # Cannot modify an immutable Sub (&foo)
&foo := {} # Cannot use bind operator ...
While a sub foo declaration generates an &foo identifier, it is deliberately neither assignable nor bindable. If you want a Callable variable, you must declare one using ordinary variable declaration.
Unbind or undefine a variable
You can't unbind variables in the sense of leaving them bound to nothing at all. (In other words, Raku avoids the billion dollar mistake.) In some cases you can rebind variables.
In some cases you can bind or assign an undefined value to a variable. If it's not a scalar variable then that's like the # variable example covered above. The scalar cases are considered next.
An example of the binding case:
my $foo := Any;
say $foo.defined; # False
say $foo; # (Any)
say $foo.VAR.WHAT; # (Any)
We'll see what the .VAR is about in a moment.
The assignment case:
my $foo = Any;
say $foo.defined; # False
say $foo.WHAT; # (Any)
say $foo.VAR.WHAT; # (Scalar)
It's important to understand that in this case the $foo is bound to a Scalar, which is a container, which is most definitely "defined", for some definition of "defined", despite appearances to the contrary in the say $foo.defined; line.
In the say $foo.WHAT; line the Scalar remains hidden. Instead we see an (Any). But the (Any) is the type of the value held inside the Scalar container bound to $foo.
In the next line we've begun to pierce the veil by calling .VAR.WHAT on $foo. The .VAR gets the Scalar to reveal itself, rather than yielding the value it contains. And so we see the type Scalar.
But if you call .defined on that Scalar it still insists on hiding!:
my $foo;
say $foo.VAR.defined; # False
say $foo.VAR.DEFINITE; # True
(The only way to force Raku to tell you the ultimate truth about its view of definiteness is to call the ultimate arbiter of definiteness, .DEFINITE.)
So what are the rules?
The compiler will let you assign or bind a given new value or container to a variable, if doing so is valid according to the original variable declaration.
Assigning or binding an undefined value follows the same rules.
Binding
All variables must be bound by the end of their declaration.
If a variable's declaration allows an undefined value to be bound/assigned to that variable, then the variable can be undefined in that sense. But in all other circumstances and senses variables themselves can never be "unbound" or "undefined".
Binding is about making a variable correspond to some container or value:
Variables with # and % sigils must be bound to a container (default Array and Hash respectively).
Variables with the $ sigil must be bound to either a container (default Scalar) or a value.
Variables with the & sigil must be bound to a Callable value or a Scalar constrained to contain a Callable value. (The & sigil'd variable that's visible as a consequence of declaring a sub does not allow rebinding or assignment.)
Assignment
Assignment means copying a value into a container.
If a variable is bound to a container, then you can assign into it, provided the assignment is allowed by the compiler according to the original variable declaration.
If a variable is not bound to a container, then the compiler will reject an assignment to it.
Scalar variables
If you use a scalar container as if it were a value, then you get the value that's held inside the container.
Binding a value (defined or undefined) to a scalar variable will mean it will stop acting as a container. If you then try to assign to that variable it won't work. You'd need to rebind it back to a container.
Footnotes
[1] In this answer I've used the word "container" to refer to any value that can serve as a container for containing other values. For example, instances of Array, Hash, or Scalar.

Determine if a variable in Raku is set

I intentionally avoid the term defined because a variable may very well have a defined value but the .defined method will return false (Failures, for instance).
Is there any way to determine whether a variable has had a value set to it?
my $foo;
say $foo; # (Any), its type object, no value assigned
my Str $bar;
say $bar; # (Str), its type object, no value assigned
my $abc = Str;
say $abc; # (Str), the type object we assigned to $abc
How can we disinguish $bar (no value set, typed as Str) from $abc (value set to Str)?
Given that $bar.WHICH == $abc.WHICH, but $bar.VAR.WHICH !== $abc.VAR.WHICH, and methods like .defined will return false for each, is there any quick and easy way to determine that there is a set value?
I supposed it could be checked against the default value, but then there'd be no way to distinguish between the value being by virtue of unset, versus by being set in code.
Variables are always set to some sort of value.
If you don't set it to a value, a value will be chosen for you.
Specifically it will be set to the default.
(If you don't choose a default, it will be set to the type object.)
my $abc;
say $abc.VAR.default.raku;
# Any
my Int $def = 42;
say $def.VAR.default.raku;
# Int
my $ghi is default(42) = 2;
say $ghi.VAR.default.raku;
# 42
What you're asking for isn't really something that Raku supports.
You could probably fake something close though.
(Every instance of Mu.new is unique.)
sub is-not-set ( Mu $_ is raw ) {
$_.self =:= $_.VAR.default
}
my $abc is default(Mu.new);
my $def is default(Mu.new) = Any;
my $ghi is default(Mu.new) = Mu.new;
say is-not-set $abc; # True
say is-not-set $def; # False
say is-not-set $ghi; # False
The thing is that assigning Nil will also set it to the default.
$def = Nil;
say is-not-set $def; # True
As will looking up the default and assigning it.
$ghi = $ghi.VAR.default;
say is-not-set $ghi; # True
I don't think you should worry about such things.
If you really really need something to happen the first time you assign to the variable, you could do something like this:
my $abc := Proxy.new(
# this FETCH only needs to return the default
# as this Proxy gets replaced upon the first assignment
FETCH => -> $ { Any },
STORE => -> $, $value {
# replace the Proxy with a new Scalar
$abc := do { my $abc = $value };
say 'first assignment just happened'
},
);
say $abc;
# Any
$abc = 1;
# first assignment just happened
say $abc;
# 1
$abc = 2;
say $abc;
# 2
The do block is just there so that $abc.VAR.name returns $abc.
Otherwise you could just write $abc := my $ = $value.
I think both the values are identical, but the containers have different type constraints.
Try
my Str $foo;
my $bar = Str;
use Test;
cmp-ok $bar, &[===], $foo, 'The values are identical';
isa-ok $bar, Str;
isa-ok $foo, Str;
isa-ok $bar.VAR.of, Mu;
nok $bar.VAR.of.isa(Str), 'The container $bar is not of Str' ;
isa-ok $foo.VAR.of, Str;
done-testing();
ok 1 - The values are identical
ok 2 - The object is-a 'Str'
ok 3 - The object is-a 'Str'
ok 4 - The object is-a 'Mu'
ok 5 - The container $bar is not of Str
ok 6 - The object is-a 'Str'
1..6
Is that a general question or an implementation problem? If the latter, maybe (ab)using roles is an option?
role isUnset {};
my Str $a = Str but isUnset;
say $a ~~ isUnset;
# meanwile
$a = 'set';
# ...
$a = Str;
# and then
say $a ~~ isUnset; # Now False
my Str $bar and my $bar = Str result in the same thing, both are of type Str but have no definite values. Str is a type object, not a value.
.defined would return True if you'd give $bar a definite value, such as "Str" (note the quotes surrounding the bareword).
You might try to assign a default value to a variable, instead of keeping it undefined:
my Str $bar is default("");
$bar will be Str only if it's assigned that value type; if its value is deleted via assigning Nil it will default again to the empty string. As a matter of fact, the default for a variable is its type object, so:
my Str $foo;
my $bar = Str;
say $foo eqv $bar
will, in fact, return True.

How to define variable names dynamically in Perl 6?

I have a name which I'd like to give to a variable, in another string variable:
my $name = '$a'; or simply my $name = 'a'; How to make the variable and to use it? I mean something like this (but it doesn't work):
my $name = '$a';
my {$name} = 1; # Doesn't work
say $a; # should be 1
A more general case. I have a list of variable names, say my #names = '$aa' ... '$cc'; How to declare and use the variable, whose name will be e.g. #names[2]?
According to documentation the lexical pad (symbol table) is immutable after compile time. Also (according to the same docs) it means EVAL cannot be used to introduce lexical symbols into the surrounding scope.
I suggest you use package variables, instead of lexical variable as suggested in the comments.
However, a workaround is possible: You can create your own lexical pad at run time (for the module requiring) using for example require MODULE:
my $name = '$a';
spurt 'MySymbols.pm6', "unit module MySymbols; use v6; my $name = 1; say \"\\$name = $name\"";
use lib '.';
require MySymbols;
Output:
$a = 1
Lexical scopes are immutable, but the way you would do it is ::($name) or MY::($name).
my $a; # required or it will generate an error
my $name = '$a';
::($name) = 1;
say $a; # 1
MY::($name) = 2;
say $a; # 2
sub foo ($name,$value) { CALLER::MY::($name) = $value }
foo($name,3);
say $a; # 3