Saya dapat memanggil metode apa saja pada Nihil dan ini terasa salah

14

Saya menghabiskan banyak waktu debugging skrip baru-baru ini, dan ketika saya akhirnya menemukan masalah itu karena kode yang terlihat seperti ini:

class Foo {
    has $.bar;
    method () {
        # do stuff
        $!.bar;
    }
}

Ternyata masalahnya adalah dengan itu $!.bar, yang seharusnya $!baratau $.bar. Saya mengerti.

Tapi mengapa ini tidak mati ?

Melihat ini secara lebih detail, sepertinya masalah di sini adalah bahwa saya sedang mencoba untuk memanggil (tidak ada) metode barpada $!, yang pada saat ini adalah Nilkarena belum ada kesalahan.

Dan sepertinya saya benar-benar dapat memanggil metode apa pun yang saya inginkan Nildan mereka semua diam-diam kembali Nil, termasuk hal-hal seperti Nil.this-is-a-fake-methoddan Nil.reverse-entropy(123).

Apakah ini fitur? Jika demikian, apa alasannya?

jja
sumber

Jawaban:

13

Ini dimaksudkan dan didokumentasikan, ya. Judul utamanya Niladalah "Tidak adanya nilai atau kegagalan jinak", dan dokumentasi kelas menyebutkan

Metode apa pun memanggil Nilmetode yang tidak ada, dan akibatnya, setiap operasi berlangganan, akan berhasil dan kembali Nil.

say Nil.ITotallyJustMadeThisUp;  # OUTPUT: «Nil␤» 
say (Nil)[100];                  # OUTPUT: «Nil␤» 
say (Nil){100};                  # OUTPUT: «Nil␤»

Sinopsis 2 menyatakan "Setiap panggilan metode tidak terdefinisi pada Nilpengembalian Nil, sehingga Nilmenyebarkan rantai panggilan metode turun. Demikian juga operasi subskripsi pada Nilpengembalian Nil", jadi maksudnya tampaknya memungkinkan ekspresi seperti $foo.Bar()[0].Baz()tanpa memerlukan pemeriksaan untuk Nilsetiap langkah, atau khusus "Nil-safe "operator panggilan dan subskripsi metode.

hobbs
sumber
4
Memang. Dan sudah lama sekali juga: github.com/rakudo/rakudo/commit/174727377f (Desember 2013) Lihat juga spekulasi terkait: design.raku.org/S02.html#Nil
Elizabeth Mattijsen
1
@ ElizabethMattijsen ah, saya pikir S02 punya jawabannya. "Setiap panggilan metode tidak terdefinisi pada Nilpengembalian Nil, sehingga Nilmenyebarkan rantai panggilan metode turun." Jadi ini dimaksudkan agar Anda dapat melakukan $foo.Bar().Baz().Blah()tanpa perlu tes nil di setiap langkah atau ?.jenis operator khusus (selama Anda benar menangani nil di akhir). Saya akan mengeditnya, terima kasih.
hobbs
1
A Nilyang tidak kesalahan dan hanya melempar kembali Nilmendapatkan penggunaan yang cukup luas di Obj-C dan NS Frameworks di mana ia digunakan dengan cara yang sama - memungkinkan untuk panggilan berantai yang terus melewati Nil. Saya tidak tahu hukuman kinerja yang tepat dari pengecualian dan menangkapnya, tetapi dugaan saya adalah bahwa Nilrantai dapat lebih efisien, jika kurang fleksibel.
user0721090601
1
(tapi itu dugaan yang sama sekali tidak diinformasikan, jadi saya senang lizmat atau jnthn memberi tahu saya bahwa saya salah dan bahwa saya perlu tutup mulut :-))
user0721090601
2
The Nilkelas memiliki FALLBACK docs.raku.org/language/typesystem#index-entry-FALLBACK_(method) metode, yang kembali Nil. Pada dasarnya, tepat sebelum pengecualian dilemparkan karena metode tidak dapat ditemukan, pemeriksaan FALLBACKdilakukan, dan dipanggil jika tersedia.
Elizabeth Mattijsen
5

Pertanyaan ini (dan jawaban hobbs) juga membuat saya merasa ... gelisah: Saya akhirnya menemukan https://docs.raku.org/language/traps : ini menjelaskan bahwa penetapan Nilmenghasilkan nilai yang berbeda, biasanya Any. Interaksi dasar REPL berikut juga menunjukkan ini:

> my $foo = Nil
(Any)

> $foo.bar
No such method 'bar' for invocant of type 'Any'
  in block <unit> at <unknown file> line 1

> my $bar := Nil
Nil

> $bar.baz
Nil

((perbedaan antara =dan :=dibahas di sini: https://docs.raku.org/language/containers#Binding ))

... jadi ide umumnya adalah bahwa 'nilai absen atau kegagalan jinak' jauh lebih luas dalam kode reguler daripada saya (dan mungkin Anda juga?) tiba-tiba takut: itu memang terjadi, ketika Anda akan bekerja dengan regex cocok secara langsung dan dalam situasi tak disengaja khusus Anda terkait dengan metode langsung memohon $!.

Ini membuat saya lebih sadar tentang perbedaan antara Nildan Any, dan alasan yang diberikan lebih masuk akal bagi saya.

chromis
sumber
2
Nilmengatur wadah ke status default-nya. Anda dapat mengubah nilai default. my $foo is default(42) = 5; $foo = Nil; say $foo; # 42
Brad Gilbert