Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Useless use of hash composer, or cannot modify an immutable hash?

Tags:

raku

This code:

constant %what = { doesn't => 'change' }; 
%what = { will => "change" } 

Should say something along the lines of "Cannot modify an immutable hash". However, it says:

Potential difficulties:
Useless use of hash composer on right side of hash assignment; did you mean := instead?

Positionals have pretty much the same problem, but the error is different. In this case it's about cannot modify an immutable, but an Str:

constant @what = <does not change>;
@what = <does change> # Cannot modify an immutable Str (does)

A Scalar works as expected. Is this a case of LTA error message, or is some container magic at work here that I'm missing?

like image 827
jjmerelo Avatar asked Mar 17 '19 19:03

jjmerelo


1 Answers

This code:

constant %what = { doesn't => 'change' }; 
%what = { will => "change" } 

Should say something along the lines of "Cannot modify an immutable hash".

Who says so? I mean this rhetorically, not rudely. I get why you think so but it's important to be careful with use of the word "should" because it implies some authority says so, eg the specification, or a design document, or someone's common sense, or whatever.


Per the current spec, and Rakudo implementation, what constant foo ... does is permanently (constantly) bind foo to some particular "value".

If that "value" is a container, then foo constantly refers to that container. (Yes, a container can be a "value", for some definition of "value" that is appropriate here.)

So your code above has changed the elements contained within that container, and that is, per spec, perfectly cromulent:

say %what; # {will => change}

In the meantime, the warning message legitimately mentions useless use of a hash constructor, plus it notes:

did you mean := instead?

If you try that:

constant %what = { doesn't => 'change' }; 
%what := { will => "change" }

You get:

Cannot use bind operator with this left-hand side

Because, as already established, %what is a compile time constant permanently bound to a hash created and initialized at compile time and that aspect -- the permanent binding of %what to that particular hash -- can't be changed during this program run.

Positionals have pretty much the same problem, but the error is different. In this case it's about cannot modify an immutable, but an Str:

constant @what = <does not change>;
@what = <does change> # Cannot modify an immutable Str (does)

That's a bit different. A constant declaration binds, regardless of whether you write = or :=. So the constant declarations are equivalent to:

constant %what := { doesn't => 'change' }
constant @what := <does not change>;

The first line binds %what to { doesn't => 'change' } which is a mutable Hash.

The second line binds @what to <does not change> which is an immutable List.

You could instead write:

constant @what = [<does not change>];
@what = <does change>;
say @what; # [does change]

A Scalar works as expected.

Not quite.

A scalar (lowercase, the generic term) does:

constant $scalar = 42;
$scalar = 99; # Cannot assign to an immutable value

Remembering that constant always binds, the above code parallels:

my $scalar := 42;
$scalar = 99; # Cannot assign to an immutable value

But a Scalar works the same as the other containers in this context:

constant $scalar = $ = 42;
$scalar = 99; # OK

(Don't write code like that unless you want to annoy people.)

Is this a case of LTA error message, or is some container magic at work?

That's a good question, and one I'm not going to try answer.

like image 66
raiph Avatar answered Nov 04 '22 01:11

raiph