«Инвокант метода« ASSIGN-KEY »должен быть экземпляром объекта» при использовании оператора присваивания

10

Хеш с набранными ключами ...

use v6;
class Foo {}
my Hash[Foo, Foo] $MAP;

my $f1 = Foo.new;
my $f2 = Foo.new;

$MAP{$f1} = $f2;

выдает ошибку:

Инвокант метода 'ASSIGN-KEY' должен быть экземпляром объекта типа 'Hash [Foo, Foo]', а не объектом типа типа 'Hash [Foo, Foo]'. Вы забыли «.new»?

Я нахожу это вводящим в заблуждение; что является настоящей ошибкой и что я должен написать вместо этого?

Я уже пробовал %сигил для хеш-переменной, которая тоже не работает.

daxim
источник
Вам говорят, что $ MAP - это класс; ОТОМХ, я бы сказал, что это роль. Вы должны создать его экземпляр. Но позвольте мне проверить.
jjmerelo

Ответы:

7

То, как вы это определили, $MAPна самом деле является ролью. Вам нужно создать (на самом деле, каламбур ) это:

class Foo {}
my Hash[Foo, Foo] $MAP;

my $map = $MAP.new;

my $f1 = Foo.new;
my $f2 = Foo.new;

$map{$f1} = $f2;
say $map;

Мертвая распродажа здесь заключалась в том, что классы не могут быть параметризованы , роли - нет.

Также:

say $MAP.DEFINITE; # False
say $map.DEFINITE; # True

Но на самом деле сообщение об ошибке было довольно информативным, вплоть до предложения использовать .new, как я делаю здесь.

Мы можем сократить его до:

class Foo {}
my %map = Hash[Foo, Foo].new ;
%map{Foo.new} = Foo.new;
%map.say;

Выполняя определение из определения, нам не нужен промежуточный класс $ MAP.

jjmerelo
источник
6

TL; DR JJ ответ правильный, но объяснение оставило меня в замешательстве. В настоящее время я вижу проблему, которую вы показывали, как сообщение об ошибке автовификации / баг и / или LTA.

say my Any       $Any;        # (Any)
say my Hash      $Hash;       # (Hash)
say my Hash[Int] $Hash-Int;   # (Hash[Int])
$Any<a>          = 42;        # OK
$Hash<a>         = 42;        # OK
$Hash-Int.new<a> = 42;        # OK
$Hash-Int<a>     = 42;        # must be an object instance, not a type object

По-моему, это ошибка или довольно близко к ней.

Ошибка / проблема применима и к массивам в том же сценарии:

say my Any       $Any;        # (Any)
say my Array     $Array;      # (Array)
say my Array[Int] $Array-Int; # (Array[Int])
$Any[42]           = 42;      # OK
$Array[42]         = 42;      # OK
$Array-Int.new[42] = 42;      # OK
$Array-Int[42]     = 42;      # Type check failed ... expected Array[Int] but got Array

Если это лучше всего считать notabug, то, возможно, сообщение об ошибке следует изменить. Хотя я согласен с JJ в том, что сообщение об ошибке действительно присутствует (когда вы понимаете, как работает raku и выясняете, что происходит), я думаю, что это, тем не менее, сообщение об ошибке LTA, если мы не изменим raku (do) на dwim.

С другой стороны, для меня не очевидно, как лучше всего улучшить сообщение об ошибке. И теперь у нас есть это ТАК. (Сравните мою точку зрения на это в ... сообщении об ошибке LTA? в недавнем ответе, который я написал .)

Другое решение

Я уже пробовал %сигил для хеш-переменной, которая тоже не работает.

JJ предоставил решение, которое инициализируется значением с явным .new. Но это снимает ограничение с переменной. Чтобы сохранить это:

class Foo {}
constant FooFoo = Hash[Foo:D,Foo:D];
my %foo is FooFoo;
%foo{Foo.new} = Foo.new;

В идеале в constantэтом нет необходимости, и, возможно, однажды это не понадобится, но я думаю, что разбор черт ограничен.

raiph
источник