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

旧时模样 提交于 2019-12-10 15:36:34

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!