„Wywoływacz metody„ ASSIGN-KEY ”musi być instancją obiektu”, gdy używany jest operator przypisania

10

Hash z wpisywanymi klawiszami…

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

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

$MAP{$f1} = $f2;

produkuje błąd:

Wywoływacz metody „ASSIGN-KEY” musi być instancją obiektu typu „Hash [Foo, Foo]”, a nie obiektem typu „Hash [Foo, Foo]”. Czy zapomniałeś „.new”?

Uważam to za mylące; jaki jest prawdziwy błąd i co mam zamiast tego napisać?

Próbowałem już %sigil dla zmiennej hash, to też nie działa.

daxim
źródło
Mówi ci, że $ MAP jest klasą; OTOMH, powiedziałbym, że to rola. Musisz to utworzyć. Ale pozwól mi sprawdzić.
jjmerelo

Odpowiedzi:

7

Sposób, w jaki go zdefiniowałeś, $MAPjest właściwie rolą. Musisz utworzyć instancję (właściwie pun ):

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

my $map = $MAP.new;

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

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

Martwa gratka polegała na tym, że klas nie można sparametryzować , role pełnią.

Również:

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

Ale tak naprawdę komunikat o błędzie był dość pouczający, łącznie z sugestią użycia .new, tak jak tutaj.

Możemy go skrócić do:

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

Wykonując wykreślanie z definicji, nie potrzebujemy klasy pośredniej $ MAP.

jjmerelo
źródło
6

TL; DR JJ odpowiedź jest słuszna, ale wyjaśnienie mnie pomieszało. Obecnie widzę problem, który pokazałeś jako komunikat o błędzie / błędzie automatycznej weryfikacji i / lub komunikat o błędzie 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

Imo, to jest błąd lub bardzo blisko jednego.

Błąd / problem dotyczy również tablic w tym samym scenariuszu:

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

Jeśli najlepiej to uznać za notabug, być może komunikat o błędzie powinien zostać zmieniony. Chociaż zgadzam się z JJ, że komunikat o błędzie jest rzeczywiście na miejscu (kiedy zrozumiesz, jak działa raku i zorientujesz się, co się dzieje), myślę, że mimo to jest to komunikat o błędzie LTA, jeśli nie zmienimy raku (do) na dwim.

Jeśli chodzi o chwytającą rękę, nie jest dla mnie oczywiste, jak najlepiej poprawić komunikat o błędzie. A teraz mamy to SO. (por. moje zdanie na ten temat w Czy komunikat o błędzie LTA? w ostatniej odpowiedzi, którą napisałem .)

Inne rozwiązanie

Próbowałem już %sigil dla zmiennej hash, to też nie działa.

JJ dostarczył rozwiązanie, które inicjuje się wartością jawną .new. Ale to usuwa ograniczenie ze zmiennej. Aby to zachować:

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

Idealnie constantnie byłoby to potrzebne, a może kiedyś nie będzie, ale myślę, że analiza cech jest ograniczona.

raiph
źródło