"L'invocant de la méthode 'ASSIGN-KEY' doit être une instance d'objet" lors de l'utilisation de l'opérateur d'affectation

10

Hash avec des touches tapées…

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

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

$MAP{$f1} = $f2;

produit l'erreur:

L'invocant de la méthode 'ASSIGN-KEY' doit être une instance d'objet de type 'Hash [Foo, Foo]', pas un objet type de type 'Hash [Foo, Foo]'. Avez-vous oublié un «.nouveau»?

Je trouve cela trompeur; quelle est la vraie erreur et que dois-je écrire à la place?

J'ai déjà essayé le %sceau pour la variable de hachage, cela ne fonctionne pas non plus.

daxim
la source
Ce que vous voyez, c'est que $ MAP est une classe; OTOMH, je dirais que c'est un rôle. Vous devez l'instancier. Mais laissez-moi vérifier.
jjmerelo

Réponses:

7

Dans la façon dont vous l'avez défini, $MAPc'est en fait un rôle. Vous devez l'instancier (en fait, le calembour ):

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

my $map = $MAP.new;

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

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

Le point mort ici était que les classes ne peuvent pas être paramétrées , les rôles le font.

Aussi:

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

Mais en fait, le message d'erreur était assez informatif, jusqu'à et y compris la suggestion d'utilisation .new, comme je le fais ici.

Nous pouvons le raccourcir à:

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

En faisant le pointage à partir de la définition, nous n'avons pas besoin de la classe intermédiaire $ MAP.

jjmerelo
la source
6

La réponse de TL; DR JJ est juste, mais l'explication m'a laissé perplexe. Je vois actuellement le problème que vous avez montré comme un message d' erreur / bogue et / ou d'erreur d' autovivification 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 c'est un bug ou assez proche d'un.

Un bogue / problème s'applique également aux tableaux dans le même scénario:

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

S'il est préférable de considérer notabug, le message d'erreur devrait peut-être être modifié. Bien que je convienne avec JJ que le message d'erreur est en fait sur le point (lorsque vous comprenez comment fonctionne raku et comprenez ce qui se passe), je pense que c'est néanmoins un message d'erreur LTA si nous ne changeons pas raku (do) en dwim.

D'un autre côté, je ne sais pas comment améliorer au mieux le message d'erreur. Et maintenant, nous avons ce SO. (cf mon point à ce sujet dans le message d'erreur LTA? dans une réponse récente que j'ai écrite .)

Une autre solution

J'ai déjà essayé le %sceau pour la variable de hachage, cela ne fonctionne pas non plus.

JJ a fourni une solution qui initialise avec une valeur avec un explicite .new. Mais cela supprime la contrainte de la variable. Pour le conserver:

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

Idéalement, le constantne serait pas nécessaire, et peut-être qu'un jour ce ne sera pas le cas, mais je pense que l'analyse des traits est limitée.

raiph
la source