“Invocante do método 'ASSIGN-KEY' deve ser uma instância de objeto” ao usar o operador de atribuição

10

Hash com teclas digitadas…

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

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

$MAP{$f1} = $f2;

produz o erro:

O invocante do método 'ASSIGN-KEY' deve ser uma instância de objeto do tipo 'Hash [Foo, Foo]', não um objeto de tipo do tipo 'Hash [Foo, Foo]'. Você esqueceu um 'novo'?

Eu acho enganoso; qual é o erro real e o que eu tenho que escrever?

Eu já tentei o %sigil para a variável hash, isso também não funciona.

daxim
fonte
O que está lhe dizendo é que $ MAP é uma classe; OTOMH, eu diria que é um papel. Você precisa instanciar isso. Mas deixe-me verificar.
jjmerelo 23/02

Respostas:

7

Da maneira que você definiu, $MAPé realmente um papel. Você precisa instanciar (na verdade, trocadilhos ):

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

my $map = $MAP.new;

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

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

O ponto morto aqui foi que as classes não podem ser parametrizadas , os papéis sim.

Além disso:

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

Mas, na verdade, a mensagem de erro foi bastante informativa, incluindo a sugestão de uso .new, como faço aqui.

Podemos reduzi-lo para:

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

Fazendo a punição da definição, não precisamos da classe intermediária $ MAP.

jjmerelo
fonte
6

A resposta de TL; DR JJ está certa, mas a explicação me deixou confusa. Atualmente, vejo o problema que você mostrou como um erro de autovivificação / bug e / ou mensagem de erro 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, este é um bug ou está bem próximo de um.

Um bug / problema também se aplica a matrizes no mesmo cenário:

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

Se for considerado melhor como não-bug, talvez a mensagem de erro deva ser alterada. Embora eu concorde com JJ que a mensagem de erro está realmente no ponto (quando você entende como o raku funciona e descobre o que está acontecendo), acho que, no entanto, é uma mensagem de erro do LTA se não mudarmos raku (do) para dwim.

Por outro lado, não é óbvio para mim como melhorar a mensagem de erro. E agora temos esse SO. (cf. meu argumento sobre isso em A mensagem de erro ... é LTA? em uma resposta recente que escrevi .)

Outra solução

Eu já tentei o %sigil para a variável hash, isso também não funciona.

JJ forneceu uma solução que inicializa com um valor com um explícito .new. Mas isso elimina a restrição da variável. Para retê-lo:

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

Idealmente, constantisso não seria necessário, e talvez um dia não seja, mas acho que a análise de características é limitada.

raiph
fonte