Бесполезное использование хеш-компоновщика, или нельзя изменить неизменный хеш? - PullRequest
4 голосов
/ 17 марта 2019

Этот код:

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

Должен сказать что-то вроде «Невозможно изменить неизменяемый хеш».Тем не менее, он говорит:

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

Позиционеры имеют почти одинаковую проблему, но ошибка другая.В этом случае он не может изменить неизменяемый объект, но Str:

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

Скаляр работает как положено.Это случай с сообщением об ошибке LTA, или здесь работает какая-то магия контейнера, которую мне не хватает?

1 Ответ

7 голосов
/ 18 марта 2019

Этот код:

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

Следует сказать что-то вроде "Невозможно изменить неизменяемый хеш".

Кто говориттак?Я имею в виду это риторически, а не грубо.Я понимаю почему вы так думаете, но важно быть осторожным с использованием слова «должен», потому что оно подразумевает, что некоторые авторитетные лица говорят так, например, спецификацию или проектный документ или чей-то здравый смысл или ...

В соответствии с текущей спецификацией и реализацией Rakudo, то, что constant foo делает, заставляет foo постоянно ссылаться на какое-то конкретное «значение» для продолжительности программы.Если это «значение» является контейнером, то foo постоянно ссылается на этот контейнер.(Да, контейнер может быть «значением» для некоторого определения «значения».)

Таким образом, ваш код, приведенный выше, с радостью изменил содержимое этого контейнера:

say %what; # {will => change}

Между тем в предупреждающем сообщении правомерно упоминается бесполезное использование хеш-конструктора, а также отмечается:

did you mean := instead?

Если вы попробуете это:

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

Вы получите:

Cannot use bind operator with this left-hand side

Поскольку, как уже установлено, %what - это постоянная времени компиляции, привязанная к хешу, созданному и инициализированному во время компиляции, и этот аспект - привязка %what к этому конкретному хешу -- не может быть изменено во время выполнения этой программы.

Позиционеры имеют почти одинаковую проблему, но ошибка другая.В этом случае он не может изменить неизменяемый объект, но Str:

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

Это немного по-другому.Декларация constant связывается независимо от того, пишете ли вы = или :=.Итак, первая строка эквивалентна:

constant @what := <does not change>;

Это может более наглядно показать, что происходит.Символ @ по умолчанию создает Array.Но если вы связываете с List, то оно обязательно связывается с List.A List является неизменным.Таким образом, следующая строка:

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

Вместо этого вы могли бы написать:

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

A Scalar работает как положено.

Itбудет потому что это не Scalar.Вместо этого вы будете говорить о скаляре, например, о скаляре Int:

my $foo = 42;       say $foo.VAR.^name;  # Scalar
constant $bar = 42; say $bar.VAR.^name;  # Int

Справедливое упоминание о неанонимном Scalar дает значение, которое оно содержит.Напротив, любое правостороннее упоминание составного контейнера дает ссылку на этот контейнер.

Аноним Scalar также дает ссылку на контейнер вместо его значения:

constant $foo = $;
$foo = 42;
say $foo; # 42

Это сообщение об ошибке LTA, или работает какое-то волшебство контейнера?

Это хороший вопрос, и я не собираюсь отвечать на него.

...