"El invocador del método 'ASSIGN-KEY' debe ser una instancia de objeto" cuando se utiliza el operador de asignación

10

Hash con teclas mecanografiadas ...

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

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

$MAP{$f1} = $f2;

produce el error:

El invocador del método 'ASSIGN-KEY' debe ser una instancia de objeto del tipo 'Hash [Foo, Foo]', no un objeto de tipo del tipo 'Hash [Foo, Foo]'. ¿Olvidaste un 'nuevo'?

Lo encuentro engañoso; ¿Cuál es el error real y qué debo escribir en su lugar?

Ya probé el %sigilo para la variable hash, que tampoco funciona.

daxim
fuente
Lo que te molesta es que $ MAP es una clase; OTOMH, diría que es un papel. Necesitas instanciarlo. Pero déjame comprobarlo.
jjmerelo

Respuestas:

7

En la forma en que lo ha definido, en $MAPrealidad es un papel. Necesitas instanciarlo (en realidad, jugarlo ):

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

my $map = $MAP.new;

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

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

El regalo muerto aquí fue que las clases no se pueden parametrizar , los roles sí.

También:

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

Pero en realidad el mensaje de error fue bastante informativo, incluida la sugerencia de uso .new, como hago aquí.

Podemos acortarlo a:

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

Al hacer el juego de palabras desde la definición, no necesitamos la clase intermedia $ MAP.

jjmerelo
fuente
6

La respuesta de TL; DR JJ es correcta, pero la explicación me dejó confundido. Actualmente veo el problema que mostró como un error / error de autovivificación y / o un mensaje de error 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, esto es un error o bastante cerca de uno.

También se aplica un error / problema para las matrices en el mismo escenario:

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

Si se considera mejor notabug, entonces tal vez se deba cambiar el mensaje de error. Si bien estoy de acuerdo con JJ en que el mensaje de error está realmente en punto (cuando entiendes cómo funciona el raku y descubres lo que está sucediendo), creo que, sin embargo, es un mensaje de error de LTA si no cambiamos el raku (do) a dwim.

Por otro lado, no es obvio para mí cómo se puede mejorar el mensaje de error. Y ahora tenemos este SO. (cf mi punto sobre eso en ¿Es el ... mensaje de error LTA? en una respuesta reciente que escribí ).

Otra solución

Ya probé el %sigilo para la variable hash, que tampoco funciona.

JJ ha proporcionado una solución que se inicializa con un valor explícito .new. Pero eso elimina la restricción de la variable. Para retenerlo:

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

Idealmente constant, no sería necesario, y tal vez algún día no sea necesario, pero creo que el análisis de rasgos es limitado.

raiph
fuente