Jenis pemeriksaan apa yang dilakukan Raku pada waktu kompilasi? Mungkinkah itu berubah di masa depan?

Aug 19 2020

Saat ini (per Agustus 2020) Rakudo tidak mengetik periksa nilai kembalian fungsi pada waktu kompilasi; artinya, ini tidak memberikan jaminan statis bahwa fungsi memenuhi batasan kembaliannya. Secara konkret, dua fungsi berikut dikompilasi sebagai Raku:

sub get-int(--> Int) { 'bug' }
sub get-int($a --> Int} { when $a == 5 { 'Rare bug' }
   default      { 42 }
}

Saya punya dua pertanyaan terkait:

  1. Adakah cara untuk mengetahui apa (jika ada) pemeriksaan tipe yang saat ini terjadi pada waktu kompilasi? (Entah melalui daftar yang telah ditulis seseorang, di suatu tempat di dokumen, atau di tempat sentral di sumber Rakudo) Atau apakah itu lebih bersifat ad hoc dari itu?

  2. Apakah kurangnya waktu kompilasi ini untuk memeriksa keputusan desain yang disengaja? Atau menambahkan lebih banyak jenis ketik statis untuk memeriksa sesuatu yang akan menyenangkan suatu hari nanti, tetapi belum diterapkan?

(Saya akrab dengan jawaban bagus Johnathan untuk Penalti kinerja untuk jenis / batasan di Raku?, Yang menyatakan bahwa "Raku mengamanatkan bahwa batasan jenis yang ditulis ke dalam program diberlakukan paling lambat saat runtime ." Jawaban itu menjelaskan berbagai cara untuk menghindari berjalan biaya -time dari typecheck, tetapi tidak menjelaskan apa, jika ada, typecheck yang dilakukan pada waktu kompilasi (yang tentunya akan menghindari biaya runtime!).)

Jawaban

12 JonathanWorthington Aug 19 2020 at 12:04

Saat ini sangat sedikit pemeriksaan jenis yang dilakukan pada waktu kompilasi; yang sebagian besar terjadi sebagai efek samping pengoptimal statis. Pemeriksaan hari ini sebagian besar tentang panggilan subrutin, di mana:

  • Kita dapat menentukan aritas panggilan dan mengetahui bahwa jumlah argumen yang diteruskan tidak akan pernah cocok
  • Kami memiliki argumen literal dan dapat melihat bahwa mereka tidak mungkin cocok dengan tanda tangannya

Ini adalah sisa dari saat pengoptimal statis melakukan lebih banyak pekerjaan inline. Saat ini, ini hanya menyebariskan operator asli pada waktu kompilasi, dan meninggalkan sisanya untuk pengoptimal dinamis VM, yang jauh lebih mampu dalam menyebariskan dan juga dapat menghapus baris (memungkinkan pengoptimalan spekulatif, tetapi juga berarti jejak tumpukan asli dapat dipulihkan, sedangkan pengoptimal statis kehilangan informasi ini).

Melakukan lebih banyak pada waktu kompilasi dianggap diinginkan, namun ada beberapa masalah praktis yang perlu dipertimbangkan.

  1. Memperkenalkan pemeriksaan tambahan juga dapat menyebabkan kerusakan kode yang berfungsi sebelumnya. Pertimbangkan modul dengan jalur kode yang akan gagal dalam pemeriksaan waktu kompilasi yang lebih ketat, tetapi itu digunakan dalam sistem yang tidak pernah mengalami kasus tersebut. Jika mulai gagal untuk mengkompilasi pada versi terbaru dari kompilator, maka akan menjadi tidak mungkin untuk menerapkan sistem itu setelah kompilator ditingkatkan. Secara umum, ini berarti pemeriksaan yang dilakukan harus berubah pada perubahan versi bahasa. (Ini masih berarti orang harus menyatakan versi bahasa yang mereka tulis saat menulis kode, pikiran.)
  2. Bahwa lebih banyak pemeriksaan yang dilakukan pada waktu kompilasi akan "pasti menghindari biaya runtime" mungkin benar, tetapi tidak sepele untuk dipikirkan. Runtime yang dikelola tidak dapat begitu saja mempercayai janji yang dibuat dalam bytecode yang diberikan, karena hal itu dapat menyebabkan pelanggaran keamanan memori (yang mengarah ke SIGSEGV atau lebih buruk). Ini cukup jelas benar dalam bahasa seperti Raku, di mana semantik pemeriksaan tipe dapat diprogram, tetapi itu benar pada JVM, CLR, dan sebagainya. Kemenangan terkait tipe terbesar di Raku berasal dari penggunaan tipe asli, yang dapat menghindari banyak alokasi dan dengan demikian pekerjaan pengumpulan sampah.
  3. Menerapkan pemeriksaan lebih lanjut akan meningkatkan kompleksitas kompilator dan juga jumlah waktu yang dibutuhkan untuk kompilasi. Yang pertama sudah menjadi masalah; bagian depan kompiler belum melihat perubahan arsitektur yang signifikan selama sekitar satu dekade. Pekerjaan RakuAST saat ini yang meletakkan fondasi untuk makro juga melibatkan penulisan ulang yang mendekati dari frontend kompilator. Arsitektur yang ditingkatkan seharusnya memudahkan penerapan pemeriksaan jenis waktu kompilasi lebih lanjut, tetapi pemikiran juga membahas bagaimana aspek kompilasi dapat diparalelkan, yang dapat memungkinkan kompilator untuk melakukan lebih banyak tanpa menambah waktu kompilasi wallclock.

Setelah perombakan frontend kompiler saat ini selesai, lebih banyak pemeriksaan waktu kompilasi yang diperkenalkan (tetapi hanya diaktifkan dari versi bahasa berikutnya) tampaknya cukup mungkin - setidaknya, selama seseorang mengerjakannya.

Namun, ada peluang yang lebih menarik lagi yang akan datang di area ini: karena akan ada API untuk program Raku, dan dengan rencana yang digabungkan untuk lolos kompiler kustom, juga akan segera memungkinkan untuk mengimplementasikan pemeriksa tipe sebagai modul ! Beberapa di antaranya mungkin mengarah pada pemeriksaan yang membuatnya menjadi versi bahasa Raku di masa mendatang. Yang lain mungkin cukup spesifik untuk domain dan ditujukan untuk memungkinkan penggunaan yang lebih tepat dari modul yang diberikan. Orang lain mungkin menerapkan kekerasan yang tidak sesuai dengan semangat bahasa dasar, tetapi beberapa pengguna bahasa mungkin ingin ikut serta.