“Invocant metode 'ASSIGN-KEY' harus berupa instance objek” saat menggunakan operator penugasan

10

Hash dengan kunci yang diketik ...

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

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

$MAP{$f1} = $f2;

menghasilkan kesalahan:

Invocant dari metode 'ASSIGN-KEY' harus berupa instance objek dari tipe 'Hash [Foo, Foo]', bukan objek tipe tipe 'Hash [Foo, Foo]'. Apakah Anda lupa 'baru'?

Saya menemukan itu menyesatkan; apa kesalahan sebenarnya dan apa yang harus saya tulis?

Saya sudah mencoba %sigil untuk variabel hash, itu juga tidak berhasil.

Daxim
sumber
Yang menarik bagi Anda adalah $ MAP adalah kelas; OTOMH, saya akan mengatakan itu peran. Anda harus instantiate. Tapi biar saya periksa.
jjmerelo

Jawaban:

7

Dalam cara Anda mendefinisikannya, $MAPsebenarnya adalah sebuah peran. Anda perlu instantiate (sebenarnya, pun ) itu:

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

my $map = $MAP.new;

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

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

Hadiah mati di sini adalah bahwa kelas tidak dapat dipisah-pisahkan , peran dilakukan.

Juga:

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

Tapi sebenarnya pesan kesalahannya cukup informatif, hingga dan termasuk saran untuk digunakan .new, seperti yang saya lakukan di sini.

Kami dapat mempersingkat menjadi:

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

Dengan melakukan penghukuman dari definisi, kita tidak memerlukan kelas menengah $ MAP.

jjmerelo
sumber
6

TL; DR JJ jawaban benar, tetapi penjelasannya membuat saya bingung. Saat ini saya melihat masalah yang Anda tunjukkan sebagai kesalahan / bug autovivification dan / atau pesan kesalahan 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 ini bug atau cukup dekat dengan satu.

Bug / masalah juga berlaku untuk array dalam skenario yang sama:

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

Jika itu dianggap terbaik notabug, maka mungkin pesan kesalahan harus diubah. Sementara saya setuju dengan JJ bahwa pesan kesalahan sebenarnya tepat (ketika Anda memahami bagaimana raku bekerja dan mencari tahu apa yang terjadi), saya pikir itu tetap merupakan pesan kesalahan LTA jika kita tidak mengubah raku (do) menjadi dwim.

Di sisi lain, tidak jelas bagiku bagaimana cara terbaik untuk memperbaiki pesan kesalahan. Dan sekarang kita punya SO ini. (cf poin saya tentang bahwa Apakah ... pesan kesalahan LTA? di jawaban terakhir saya menulis .)

Solusi lain

Saya sudah mencoba %sigil untuk variabel hash, itu juga tidak berhasil.

JJ telah memberikan solusi yang menginisialisasi dengan nilai dengan eksplisit .new. Tapi itu menghilangkan batasan dari variabel. Untuk mempertahankannya:

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

Idealnya constanttidak diperlukan, dan mungkin suatu hari tidak, tetapi saya pikir penguraian sifat terbatas.

raiph
sumber