问题
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?
回答1:
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...
Per the current spec, and Rakudo implementation, what constant foo
does is make foo
constantly refer to some particular "value" for the duration of the program. 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".)
So your code above has happily changed the content of that container:
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 bound to a hash created and initialized at compile time and that aspect -- the 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 first line is equivalent to:
constant @what := <does not change>;
This may more clearly show what's happening. The @
symbol by default creates an Array
. But if you bind to a List
it's bound to that List
. A List
is immutable. So the next line becomes:
@what = <does change> # Cannot modify an immutable Str (does)
You could instead write:
constant @what = [<does not change>];
@what = <does change>;
say @what; # [does change]
A
Scalar
works as expected.
It'll be because it's not a Scalar
. Instead, you'll be speaking of a scalar, eg a scalar Int
:
my $foo = 42; say $foo.VAR.^name; # Scalar
constant $bar = 42; say $bar.VAR.^name; # Int
A right hand side mention of a non-anonymous Scalar
yields the value it contains. In contrast, any right hand side mention of composite container yields a reference to that container.
An anonymous Scalar
also yields a reference to the container instead of its value:
constant $foo = $;
$foo = 42;
say $foo; # 42
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.
来源:https://stackoverflow.com/questions/55211168/useless-use-of-hash-composer-or-cannot-modify-an-immutable-hash