Design: call_indirect versus abstraksi

Dibuat pada 7 Mei 2020  ·  36Komentar  ·  Sumber: WebAssembly/design

call_indirect telah menjadi fitur yang sangat berguna untuk WebAssembly. Namun, efisiensi dan perilaku instruksi yang baik secara implisit bergantung pada kesederhanaan sistem tipe wasm. Secara khusus, setiap nilai wasm memiliki tepat satu tipe (statis) miliknya. Properti ini dengan mudah menghindari sejumlah masalah yang diketahui dengan panggilan fungsi yang tidak diketik dalam bahasa yang diketik. Tapi sekarang wasm melampaui tipe numerik, itu telah sampai pada titik di mana kita perlu memahami masalah ini dan mengingatnya.

call_indirect dasarnya bekerja dengan membandingkan tanda tangan yang diharapkan dari pemanggil dengan tanda tangan yang ditentukan oleh pemanggil. Dengan hanya tipe numerik, WebAssembly memiliki properti bahwa tanda tangan ini sama jika dan hanya jika panggilan langsung ke fungsi yang dirujuk oleh funcref akan diperiksa tipenya. Tetapi ada dua alasan yang akan segera tidak benar:

  1. Dengan subtipe, panggilan langsung akan berfungsi selama tanda tangan yang ditentukan fungsi sebenarnya adalah "sub-tanda tangan" dari tanda tangan yang diharapkan, artinya semua tipe input adalah subtipe dari tipe parameter fungsi dan semua tipe output adalah supertipe dari fungsi jenis hasil. Ini berarti bahwa pemeriksaan kesetaraan antara tanda tangan yang diharapkan dari panggilan tidak langsung dan tanda tangan yang ditentukan fungsi akan menjebak dalam sejumlah situasi yang sangat aman, yang mungkin bermasalah untuk mendukung bahasa dengan penggunaan subtipe dan panggilan tidak langsung yang berat (seperti yang diangkat selama diskusi tentang menunda subtipe). Ini juga berarti bahwa, jika modul dengan sengaja mengekspor fungsi dengan tanda tangan yang lebih lemah daripada fungsi yang didefinisikan, maka call_indirect dapat digunakan untuk mengakses fungsi dengan tanda tangan yang ditentukan secara pribadi daripada hanya tanda tangan publik yang lebih lemah ( masalah yang baru saja ditemukan dan belum dibahas).
  2. Dengan impor tipe, modul dapat mengekspor tipe tanpa mengekspor definisi tipe itu, memberikan abstraksi yang sangat diandalkan oleh sistem seperti WASI. Abstraksi itu mencegah modul lain bergantung pada definisi khususnya pada waktu kompilasi . Tetapi pada saat dijalankan, tipe abstrak yang diekspor hanya diganti dengan definisinya. Ini penting, misalnya, untuk mengaktifkan call_indirect agar berfungsi dengan baik pada fungsi yang diekspor yang tanda tangan yang diekspor merujuk pada jenis yang diekspor. Namun, jika modul jahat mengetahui definisi tipe yang diekspor itu, mereka dapat menggunakan call_indirect untuk mengonversi bolak-balik antara tipe yang diekspor dan definisi yang dimaksudkan untuk menjadi rahasia karena call_indirect hanya membandingkan tanda tangan pada saat dijalankan, ketika kedua jenis tersebut memang sama . Dengan demikian modul jahat dapat menggunakan call_indirect untuk mengakses rahasia yang dimaksudkan untuk diabstraksikan oleh tipe yang diekspor, dan dapat menggunakan call_indirect untuk memalsukan nilai dari tipe yang diekspor yang mungkin melanggar invarian kritis keamanan yang tidak ditangkap di definisi tipe itu sendiri.

Dalam kedua situasi di atas, call_indirect dapat digunakan untuk melewati abstraksi tanda tangan yang diekspor modul. Seperti yang saya sebutkan, sejauh ini tidak menjadi masalah karena wasm hanya memiliki tipe numerik. Dan awalnya saya berpikir bahwa, dengan menunda subtipe, semua kekhawatiran tentang call_indirect juga telah ditangguhkan secara efektif. Tetapi yang baru-baru ini saya sadari adalah, dengan menghapus subtipe, tipe "baru" (bernama externref di https://github.com/WebAssembly/reference-types/pull/87) secara efektif merupakan pengganti untuk impor tipe abstrak. Jika itu yang diinginkan orang, sayangnya kita perlu mempertimbangkan interaksi di atas antara call_indirect dan jenis impor.

Sekarang ada banyak cara potensial untuk mengatasi masalah di atas dengan call_indirect , tetapi masing-masing memiliki pengorbanannya, dan itu terlalu besar ruang desain untuk dapat mengambil keputusan dengan cepat. Jadi saya tidak menyarankan agar kita memecahkan masalah ini di sini dan sekarang. Sebaliknya, keputusan yang harus dibuat saat ini adalah apakah akan mengulur waktu untuk menyelesaikan masalah dengan benar sehubungan dengan externref . Khususnya, jika untuk saat ini kami membatasi call_indirect dan func.ref hanya untuk memeriksa jenis ketika tanda tangan terkait seluruhnya numerik, maka kami melayani semua kasus penggunaan inti-wasm dari panggilan tidak langsung dan pada waktu yang sama meninggalkan ruang untuk semua solusi potensial untuk masalah di atas. Namun, saya tidak tahu apakah pembatasan ini praktis, baik dari segi upaya implementasi maupun dalam hal apakah itu menghalangi aplikasi externref yang ditunggu-tunggu orang. Alternatifnya adalah membiarkan call_indirect dan func.ref apa adanya. Mungkin saja ini berarti bahwa, tergantung pada solusi yang kami dapatkan, externref mungkin tidak dapat dibuat instan seperti impor tipe sebenarnya, dan/atau externref mungkin (ironisnya) tidak dapat memiliki supertipe apa pun (misalnya mungkin tidak dapat menjadi subtipe anyref jika kita akhirnya memutuskan untuk menambahkan anyref ).

Saya, berbicara untuk diri saya sendiri, menganggap kedua opsi dapat dikelola. Meskipun saya memiliki preferensi, saya tidak terlalu memaksakan keputusan untuk mengambil satu atau lain cara, dan saya yakin Anda semua memiliki akses yang lebih baik ke informasi yang diperlukan untuk mengambil keputusan yang terinformasi dengan baik. Saya hanya ingin Anda semua tahu bahwa ada keputusan yang harus dibuat, dan pada saat yang sama saya ingin membangun kesadaran tentang masalah menyeluruh dengan call_indirect . Jika Anda menginginkan penjelasan yang lebih menyeluruh tentang masalah itu daripada yang diberikan oleh ringkasan di atas, silakan baca yang berikut ini.

call_indirect versus Abstraksi, secara Detail

Saya akan menggunakan notasi call_indirect[ti*->to*](func, args) , di mana [ti*] -> [to*] adalah tanda tangan yang diharapkan dari fungsi tersebut, func hanyalah sebuah funcref (bukan tabel funcref dan indeks), dan args adalah nilai to* untuk diteruskan ke fungsi. Demikian pula, saya akan menggunakan call($foo, args) untuk panggilan langsung fungsi dengan indeks $foo lewat argumen args .

Sekarang anggaplah $foo adalah indeks fungsi dengan tipe input yang dideklarasikan ti* dan tipe output to* . Anda mungkin berharap bahwa call_indirect[ti*->to*](ref.func($foo), args) setara dengan call($foo, args) . Memang, itulah yang terjadi sekarang. Tetapi tidak jelas apakah kita dapat mempertahankan perilaku itu.

call_indirect dan Pengetikan

Salah satu contoh masalah potensial muncul dalam diskusi tentang subtipe. Misalkan berikut ini:

  • tsub adalah subtipe dari tsuper
  • modul instance IA mengekspor fungsi $fsub yang didefinisikan dengan tipe [] -> [tsub]
  • modul MB mengimpor fungsi $fsuper dengan tipe [] -> [tsuper]
  • modul instance IB adalah modul MB yang dibuat dengan $fsub IA sebagai $fsuper (yang mungkin dilakukan—bahkan jika itu tidak mungkin sekarang, masalah ini adalah tentang potensi masalah yang akan datang )

Sekarang pertimbangkan apa yang harus terjadi jika IB mengeksekusi call_indirect[ -> tsuper](ref.func($fsuper)) . Berikut adalah dua hasil yang tampaknya paling masuk akal:

  1. Panggilan berhasil karena tanda tangan yang diharapkan dan tanda tangan yang ditentukan kompatibel.
  2. Jebakan panggilan karena dua tanda tangan berbeda.

Jika kita memilih hasil 1, sadarilah bahwa kita mungkin perlu menggunakan salah satu dari dua teknik untuk memungkinkan hal ini:

  1. Untuk fungsi yang diimpor, bandingkan call_indirect dengan tanda tangan impor daripada tanda tangan definisi.
  2. Lakukan pemeriksaan run-time setidaknya linier untuk kompatibilitas subtipe dari tanda tangan yang diharapkan dan tanda tangan definisi.

Jika Anda lebih suka teknik 1, sadari bahwa itu tidak akan berhasil setelah kita menambahkan Referensi Fungsi yang Diketik (dengan subtipe varian). Artinya, func.ref($fsub) akan menjadi ref ([] -> [tsub]) dan juga ref ([] -> [tsuper]) , namun teknik 1 tidak akan cukup untuk mencegah call_indirect[ -> super](ref.func($fsub)) dari perangkap. Ini berarti hasil 1 kemungkinan membutuhkan teknik 2, yang memiliki implikasi kinerja yang memprihatinkan.

Jadi mari kita pertimbangkan hasil 2 sedikit lagi. Teknik implementasi di sini adalah untuk memeriksa apakah tanda tangan yang diharapkan dari call_indirect di IB sama dengan tanda tangan dari definisi $fsub di IA. Pada awalnya kelemahan utama dari teknik ini mungkin tampak bahwa ia menjebak sejumlah panggilan yang aman untuk dieksekusi. Namun, kelemahan lainnya adalah berpotensi menimbulkan kebocoran keamanan untuk IA.

Untuk melihat caranya, mari kita ubah sedikit contoh kita dan anggaplah bahwa, meskipun instance IA secara internal mendefinisikan $fsub memiliki tipe [] -> [tsub] , instance IA hanya mengekspornya dengan tipe [] -> [tsuper] . Menggunakan teknik untuk hasil 2, contoh IB dapat (secara jahat) mengeksekusi call_indirect[ -> tsub]($fsuper) dan panggilan akan berhasil. Artinya, IB dapat menggunakan call_indirect untuk menghindari penyempitan yang dilakukan IA pada tanda tangan fungsinya. Paling-paling, itu berarti IB bergantung pada aspek IA yang tidak dijamin oleh tanda tangan IA. Paling buruk, IB dapat menggunakan ini untuk mengakses status internal yang mungkin sengaja disembunyikan IA.

call_indirect dan Ketik Impor

Sekarang mari kita kesampingkan subtipe dan pertimbangkan jenis impor. Untuk kenyamanan, saya akan berbicara tentang impor tipe, bukan hanya impor tipe referensi, tetapi detail itu tidak penting. Untuk menjalankan contoh di sini, misalkan berikut ini:

  • modul instance IC mendefinisikan tipe capability dan mengekspor tipe tetapi bukan definisinya sebagai $handle
  • modul instance IC mengekspor fungsi $do_stuff yang didefinisikan dengan tipe [capability] -> [] tetapi diekspor dengan tipe [$handle] -> []
  • module MD mengimpor tipe $extern dan fungsi $run dengan tipe [$extern] -> []
  • ID instance modul adalah modul MD yang dipakai dengan IA yang diekspor $handle sebagai $extern dan dengan IA yang diekspor $do_stuff sebagai $run

Apa yang diatur oleh contoh ini adalah dua modul di mana satu modul melakukan hal-hal dengan nilai modul lain tanpa mengetahui atau diizinkan untuk mengetahui nilai-nilai itu. Misalnya, pola ini merupakan dasar yang direncanakan untuk berinteraksi dengan WASI.

Sekarang misalkan ID instance telah berhasil mendapatkan nilai e bertipe $extern dan mengeksekusi call_indirect[$extern -> ](ref.func($run), e) . Berikut adalah dua hasil yang tampaknya paling masuk akal:

  1. Panggilan berhasil karena tanda tangan yang diharapkan dan tanda tangan yang ditentukan kompatibel.
  2. Jebakan panggilan karena dua tanda tangan berbeda.

Hasil 2 membuat call_indirect sangat tidak berguna dengan tipe yang diimpor. Jadi untuk hasil 1, sadari bahwa tipe input $extern bukan tipe input yang ditentukan dari $do_stuff (yang sebaliknya adalah capability ), jadi kita mungkin perlu menggunakan salah satu dari dua teknik untuk menjembatani kesenjangan ini:

  1. Untuk fungsi yang diimpor, bandingkan call_indirect dengan tanda tangan impor daripada tanda tangan definisi.
  2. Ketahuilah bahwa pada saat run time tipe $extern dalam instance ID mewakili capability .

Jika Anda lebih suka teknik 1, sadari bahwa itu sekali lagi tidak akan berfungsi setelah kita menambahkan Referensi Fungsi yang Diketik. (Alasan dasarnya sama dengan subtipe, tetapi akan membutuhkan lebih banyak teks untuk mengilustrasikan analog di sini.)

Itu meninggalkan kita dengan teknik 2. Sayangnya, sekali lagi ini menghadirkan masalah keamanan potensial. Untuk mengetahui alasannya, anggaplah ID berbahaya dan ingin mendapatkan isi $handle yang telah dirahasiakan IC. Misalkan lebih lanjut bahwa ID memiliki tebakan yang baik tentang apa yang sebenarnya diwakili oleh $handle , yaitu capability . ID dapat mendefinisikan fungsi identitas $id_capability bertipe [capability] -> [capability] . Diberikan nilai e bertipe $extern , ID kemudian dapat mengeksekusi call_indirect[$extern -> capability](ref.func($id_capability), e) . Menggunakan teknik 2, panggilan tidak langsung ini akan berhasil karena $extern merepresentasikan capability pada saat run time, dan ID akan mendapatkan capability mentah yang direpresentasikan kembali oleh e . Demikian pula, diberi nilai c bertipe capability , ID dapat mengeksekusi call_indirect[capability -> $extern](ref.func($id_capability), c) untuk memalsukan c menjadi $extern .

Kesimpulan

Mudah-mudahan saya telah menjelaskan bahwa call_indirect memiliki sejumlah masalah kinerja, semantik, dan/atau keamanan/abstraksi mendatang yang signifikan—masalah yang sejauh ini beruntung dapat dihindari oleh WebAssembly. Sayangnya, karena call_indirect menjadi bagian dari WebAssembly inti, masalah ini memotong sejumlah proposal yang sedang diproses. Saat ini, saya pikir akan lebih baik untuk fokus pada proposal yang paling mendesak, Jenis Referensi, di mana kita perlu memutuskan apakah akan membatasi call_indirect dan func.ref hanya untuk tipe numerik call_indirect .

(Maaf untuk posting yang panjang. Saya mencoba yang terbaik untuk menjelaskan interaksi kompleks dari fitur kompilasi-waktu-mengetik-meet-run-time-mengetik lintas-modul dan menunjukkan pentingnya interaksi tersebut sesingkat mungkin.)

Komentar yang paling membantu

Di sisi lain, Anda telah menunjukkan bahwa anyref castable dapat digunakan untuk menghindari mekanisme abstraksi statis.

Abstraksi tipe statis tidak cukup dalam bahasa dengan gips tipe dinamis. Karena abstraksi statis bergantung pada parametrik, dan gips memecahkannya. Tidak ada yang baru tentang itu, makalah telah ditulis tentang itu. Mekanisme abstraksi lain diperlukan dalam konteks seperti itu.

Mencoba mengatasinya dengan membatasi penggunaan tipe abstrak mengalahkan tujuannya. Pertimbangkan kasus penggunaan WASI. Seharusnya tidak masalah apakah modul WASI dan jenis apa pun yang diekspornya diimplementasikan oleh host atau di Wasm. Jika Anda secara sewenang-wenang membatasi tipe abstrak yang ditentukan pengguna, maka implementasi Wasm tidak lagi dapat dipertukarkan dengan implementasi host secara umum.

  1. Itu tidak membantu membuat call_indirect menghormati subtipe (yang saya pikir sudah Anda katakan secara eksplisit)

Hah? Ini adalah bagian dari aturan subtipe, begitu juga menurut definisi.

  1. Itu tidak mencegah call_indirect digunakan untuk menggunakan fungsi yang diekspor dengan tanda tangan yang ditentukan daripada tanda tangan yang diekspor.

Saya tidak mengatakan itu. Saya mengatakan bahwa ini bukan masalah dengan call_indirect itu sendiri, tetapi pertanyaan tentang memilih mekanisme abstraksi tipe yang sesuai untuk bahasa dengan gips.

Selain itu, tidak ada alasan kuat mengapa kompilasi OCaml (atau bahasa serupa lainnya) memerlukan pengenalan tipe varian. Bahkan jika itu bisa sedikit lebih cepat secara teori (yang saya ragu akan terjadi pada mesin generasi saat ini, kemungkinan besar sebaliknya), tipe varian adalah komplikasi signifikan yang seharusnya tidak diperlukan untuk MVP. Saya tidak cukup berbagi selera Anda untuk kompleksitas prematur. ;)

Persamaan kembali pada fungsi: ada bahasa, seperti Haskell atau SML, yang tidak mendukungnya, jadi mungkin mendapat manfaat langsung dari referensi func. OCaml melempar untuk kesetaraan struktural dan secara eksplisit memiliki perilaku yang ditentukan implementasi untuk yang fisik. Itu dibiarkan terbuka apakah itu memungkinkan selalu mengembalikan false atau melempar untuk fungsi, tetapi keduanya mungkin cukup dalam praktiknya, dan perlu ditelusuri sebelum melakukan pembungkus ekstra yang mahal.

[Sebagai komentar meta, saya akan sangat menghargai jika Anda mengurangi kuliah Anda dan mungkin mempertimbangkan gagasan bahwa ini adalah dunia di mana, mungkin, kumpulan orang yang kompeten tidak tunggal dan jejak otak kadang-kadang telah diterapkan sebelumnya.]

Semua 36 komentar

Terima kasih atas tulisan terperinci ini, Ross! Saya punya pertanyaan kecil: di bagian " call_indirect and Type Imports" Anda menulis,

Jika Anda lebih suka teknik 1, sadari bahwa itu sekali lagi tidak akan berfungsi setelah kita menambahkan Referensi Fungsi yang Diketik.

Apakah ini juga tunduk pada peringatan dari bagian sebelumnya bahwa masalahnya hanya muncul setelah kita menambahkan subtipe varian ke referensi fungsi yang diketik?

Bukan itu. Semua masalah di bagian subtipe tidak tergantung pada jenis impor, dan semua masalah di bagian jenis impor tidak tergantung pada subtipe. Sehubungan dengan masalah khusus yang Anda tanyakan, pertimbangkan bahwa nilai tipe ref ([] -> [capability]) dapat dikembalikan oleh fungsi yang diekspor sebagai nilai tipe ref ([] -> [$handle]) , yang kemudian dapat diubah menjadi funcref dan secara tidak langsung dipanggil ke. Berbeda dengan fungsi yang diekspor, perubahan dalam perspektif nilai ini terjadi pada waktu proses daripada waktu tautan, jadi kami tidak dapat menyelesaikannya dengan membandingkan dengan tanda tangan impor karena referensi fungsi tidak pernah diimpor sendiri.

module instance IC defines a type capability and exports the type but not its definition as $handle
Bagaimana ini akan berhasil? Perlu ada sesuatu yang menghubungkan capability dan $handle agar IC tahu bagaimana menghadapinya?
Juga berdasarkan https://github.com/WebAssembly/proposal-type-imports/blob/master/proposals/type-imports/Overview.md#exports , tipe yang diimpor sepenuhnya abstrak. Jadi meskipun $capability diekspor, itu abstrak. Mungkin saya salah paham tentang sesuatu.

Pertanyaan serupa untuk mengekspor module instance IC exports a function $do_stuff that was defined with type [capability] -> [] but exported with type [$handle] -> [] .

Saya dapat membayangkan semacam hubungan subtipe yang digunakan untuk ini, misalnya jika $capability <: $handle , maka kita dapat export $capability as $handle . Tapi awal bagian ini disebutkan untuk mengesampingkan subtipe, jadi saya mengesampingkannya... Tapi saya juga memikirkannya lebih jauh:
Jika: $capability <: $handle , kita dapat export $capability as $handle , tetapi export ([$capability] -> []) as ([$handle] -> []) harus "gagal" karena fungsi bertentangan dalam argumen.

Dengan jenis ekspor, modul menentukan tanda tangan, seperti type $handle; func $do_stuff_export : [$handle] -> [] , dan kemudian membuat instance tanda tangan, seperti type $handle := capability; func $do_stuff_export := $do_stuff . (Abaikan sintaks spesifik sepenuhnya.) Pemeriksa tipe kemudian memeriksa "mengingat bahwa $handle mewakili capability dalam modul ini, apakah ekspor func $do_stuff_export := $do_stuff valid dalam modul ini?". Karena tipe $do_stuff adalah [capability] -> [] , tanda tangannya sejajar persis dengan $do_stuff_export setelah membuat instance $handle dengan capability , jadi cek berhasil. (Tidak ada subtipe yang terlibat di sini, hanya substitusi variabel.)

Namun, perhatikan bahwa tanda tangan itu sendiri tidak mengatakan apa pun tentang $handle . Ini berarti bahwa semua orang seharusnya memperlakukan $handle sebagai tipe abstrak. Artinya, tanda tangan dengan sengaja mengabstraksi detail implementasi modul, dan semua orang seharusnya menghormati abstraksi itu. Tujuan dari masalah ini adalah untuk mengilustrasikan bahwa call_indirect dapat digunakan untuk menghindari abstraksi tersebut.

Semoga itu menjelaskan masalah ini sedikit!

Terima kasih, itu menjelaskan banyak hal. Saya akan memiliki pertanyaan tentang bagian subtipe (maaf melompat-lompat):

Saya mengikuti skenario di mana kita ingin IB mengeksekusi call_indirect[ -> tsuper](ref.func($fsuper)) berhasil, dengan meminta call_indirect "bandingkan dengan tanda tangan impor daripada tanda tangan definisi."

Dan Anda menambahkan bahwa (karena referensi fungsi yang diketik) kami juga membutuhkan

  1. Lakukan pemeriksaan run-time setidaknya linier untuk kompatibilitas subtipe dari tanda tangan yang diharapkan dan tanda tangan definisi.

Haruskah ini menjadi kompatibilitas antara "tanda tangan yang diharapkan dan tanda tangan impor "? Karena kami mengasumsikan kami telah membuat call_indirect membandingkan tanda tangan impor dengan tanda tangan yang diharapkan.

Jika kompatibilitas diperiksa antara yang diharapkan dan impor, maka nanti, call_indirect[ -> tsub]($fsuper) akan gagal.

Teknik 1 dan 2 diberikan sebagai dua cara ortogonal untuk membuat panggilan tidak langsung itu bekerja. Sayangnya, teknik 1 tidak sesuai dengan referensi fungsi yang diketik, dan teknik 2 kemungkinan terlalu mahal. Jadi tak satu pun dari ini tampaknya akan berhasil. Jadi sisa bagian ini mempertimbangkan apa yang terjadi jika kita tidak menggunakan keduanya dan tetap menggunakan perbandingan kesetaraan sederhana antara tanda tangan yang diharapkan dan yang ditentukan. Maaf bila membingungkan; tidak memiliki semantik yang direncanakan berarti saya harus membahas tiga semantik potensial.

Berhati-hatilah untuk tidak melompat ke terlalu banyak kesimpulan. ;)

Asumsi saya adalah bahwa call_indirect harus tetap secepat hari ini dan oleh karena itu hanya memerlukan tes kesetaraan tipe, tidak peduli berapa banyak subtipe yang kita tambahkan ke bahasa. Pada saat yang sama, pemeriksaan runtime harus koheren dengan sistem tipe statis, yaitu harus menghormati hubungan subtipe.

Sekarang, persyaratan yang tampaknya kontradiktif ini sebenarnya dapat didamaikan dengan cukup mudah, selama kita memastikan bahwa tipe yang dapat digunakan dengan call_indirect selalu berada di daun hierarki subtipe.

Salah satu cara yang mapan untuk menegakkannya adalah dengan memperkenalkan gagasan tipe _exact_ ke dalam sistem tipe. Tipe yang tepat tidak memiliki subtipe, hanya supertipe, dan kita akan memiliki (exact T) <: T .

Dengan itu, kita dapat meminta tipe target di call_indirect menjadi tipe yang tepat. Lebih jauh lagi, tipe fungsi itu sendiri secara alami adalah tipe yang tepat dari fungsi itu.

Sebuah modul juga bisa memerlukan tipe yang tepat pada impor fungsi, jika ingin memastikan bahwa itu hanya dapat dipakai dengan fungsi yang berhasil pemeriksaan runtime yang dimaksudkan.

Itu saja yang diperlukan untuk memastikan bahwa teknik implementasi saat ini dari perbandingan pointer sederhana pada tipe fungsi kanonik tetap valid. Itu tidak tergantung pada subtipe lain yang ada, atau seberapa mewah kita membuat subtipe fungsi. (FWIW, saya membahas ini dengan Luke beberapa waktu lalu, dan berencana untuk membuat PR, tetapi diblokir karena menunggu perubahan pada cerita subtipe, dan proposal mana yang sekarang dipindahkan.)

(Satu kelemahannya adalah bahwa menyempurnakan definisi fungsi ke subtipe tidak lagi merupakan perubahan yang kompatibel ke belakang secara umum, setidaknya tidak jika tipe persisnya telah digunakan di mana saja. Tetapi kelemahan itu tidak dapat dihindari di bawah batasan kami, terlepas dari bagaimana tepatnya kami menegakkan mereka.)

Beberapa selain:

Alternatifnya adalah membiarkan call_indirect dan func.ref apa adanya.

AFAICS, tidak layak untuk melarang ref.func pada fungsi yang melibatkan tipe referensi. Itu akan sangat melumpuhkan banyak kasus penggunaan, yaitu, segala sesuatu yang melibatkan fungsi kelas satu yang beroperasi pada externref (callback, hook, dll.).

Mungkin saja ini berarti bahwa, tergantung pada solusi yang kami dapatkan, externref mungkin tidak dapat dibuat instan seperti impor tipe sebenarnya, dan/atau externref mungkin (ironisnya) tidak dapat memiliki supertipe apa pun (mis. dapat menjadi subtipe anyref jika kita akhirnya memutuskan untuk menambahkan anyref).

Bisakah Anda menguraikan? Saya tidak melihat hubungannya.

Berhati-hatilah untuk tidak melompat ke terlalu banyak kesimpulan. ;)

Saya tidak yakin kesimpulan apa yang Anda maksud. Kesimpulan yang saya nyatakan adalah bahwa ada sejumlah masalah dengan call_indirect yang perlu kita waspadai dan harus mulai direncanakan. Anda tampaknya menyarankan bahwa masalah ini tidak penting karena Anda memiliki solusi dalam pikiran. Tetapi solusi itu belum ditinjau atau diterima oleh CG, dan kita tidak boleh merencanakannya sampai ada. Saya secara khusus meminta untuk tidak membahas solusi karena akan membutuhkan waktu untuk mengevaluasi dan membandingkannya dan ada keputusan yang perlu kita buat sebelum kita punya waktu untuk melakukan evaluasi dan perbandingan tersebut dengan benar. Namun, untuk mencegah orang membentuk persepsi bahwa masalah ini telah diselesaikan dan akibatnya menghindari keputusan yang mendesak, saya akan membahas solusi Anda sebentar.

Salah satu cara yang mapan untuk menegakkannya adalah dengan memperkenalkan gagasan tipe eksak ke dalam sistem tipe.

Jenis yang tepat bukanlah solusi yang mapan. Jika ada, jenis yang tepat telah menimbulkan masalah yang masih diusahakan oleh para pendukungnya untuk diatasi. Menariknya, di sini adalah thread di mana tim naskah awalnya melihat bagaimana jenis bentuk yang tepat yang Anda mengusulkan sedang bisa memecahkan beberapa masalah, tapi kemudian mereka akhirnya [menyadari) (https://github.com/microsoft/TypeScript/issues/12936 #issuecomment-284590083) bahwa tipe yang tepat menimbulkan lebih banyak masalah daripada yang mereka pecahkan. (Catatan untuk konteks: diskusi itu didorong oleh tipe objek persis Flow, yang sebenarnya bukan bentuk tipe persis (dalam pengertian teoretis) tetapi sebaliknya hanya melarang analog objek dari subtipe awalan.) Saya bisa membayangkan kita memutar ulang utas itu di sini.

Sebagai contoh bagaimana masalah semacam ini dapat terjadi untuk WebAssembly, misalkan kami tidak menunda subtipe. Jenis ref.null akan menjadi exact nullref menggunakan jenis yang tepat. Tapi exact nullref tidak akan menjadi subtipe dari exact anyref . Faktanya, menurut semantik biasa dari tipe yang tepat, kemungkinan tidak ada nilai yang menjadi milik exact anyref karena kemungkinan tidak ada tipe run-time nilai yang persis anyref . Ini akan membuat call_indirect sama sekali tidak dapat digunakan selama anyref s.

Sekarang mungkin Anda memiliki beberapa versi yang berbeda dari tipe yang tepat dalam pikiran, tetapi akan memakan waktu cukup lama untuk memeriksa bahwa versi yang berbeda ini entah bagaimana mengatasi banyak masalah terbuka dengan tipe yang tepat. Jadi poin saya di sini bukan untuk membuang solusi ini, tetapi mengakui bahwa itu tidak jelas bahwa ini adalah solusi dan untuk tidak membuat keputusan dengan harapan bahwa.

Bisakah Anda menguraikan? Saya tidak melihat hubungannya.

Anda mengacu pada kalimat yang panjang. Bagian mana yang Anda ingin saya jelaskan? Satu tebakan adalah Anda mungkin melewatkan masalah keseluruhan dengan call_indirect dan mengetikkan impor. Saran tipe persis Anda hanya mengatasi masalah dengan subtipe, tetapi kami menetapkan di atas bahwa call_indirect memiliki masalah bahkan tanpa subtipe apa pun.

Itu akan sangat melumpuhkan banyak kasus penggunaan, yaitu, segala sesuatu yang melibatkan fungsi kelas satu yang beroperasi pada externref (callback, hook, dll.).

Ya, jadi ini adalah sesuatu yang saya harapkan untuk mendapatkan informasi lebih lanjut. Pemahaman saya adalah bahwa kasus penggunaan utama call_indirect adalah untuk mendukung pointer fungsi C/C++ dan metode virtual C++. Pemahaman saya juga bahwa kasus penggunaan ini saat ini terbatas pada tanda tangan numerik. Saya tahu kegunaan lebih potensial dari call_indirect , tapi seperti yang saya sebutkan saya menyarankan pembatasan sementara, jadi yang penting adalah apa saja kegunaan saat ini call_indirect . Mengingat call_indirect masih memerlukan tabel dan indeks daripada hanya funcref , tampaknya tidak dirancang dengan baik untuk mendukung panggilan balik. Saya tidak tahu apakah itu karena saat ini tidak digunakan untuk tujuan ini.

Anda semua tahu basis kode yang menargetkan fitur ini jauh lebih baik daripada saya, jadi jika Anda tahu beberapa program nyata yang membutuhkan fungsi ini sekarang, akan sangat membantu untuk memberikan beberapa contoh pola penggunaan yang dibutuhkan di sini. Selain berguna untuk mengetahui apakah kita perlu mendukung fungsi ini sekarang, jika fungsi itu diperlukan sekarang, maka contoh-contoh ini akan membantu dalam menginformasikan cara terbaik untuk menyediakannya dengan cepat sambil mengatasi masalah di atas.

@RossTate :

Jika ada, jenis yang tepat telah menimbulkan masalah yang masih diusahakan oleh para pendukungnya untuk diatasi. Menariknya, ini adalah utas di mana tim TypeScript awalnya melihat bagaimana tipe tepat dari formulir yang Anda usulkan dapat memecahkan beberapa masalah, tetapi kemudian mereka akhirnya menyadari bahwa tipe yang tepat menimbulkan lebih banyak masalah daripada yang mereka pecahkan. (Catatan untuk konteks: diskusi itu didorong oleh tipe objek persis Flow, yang sebenarnya bukan bentuk tipe persis (dalam pengertian teoretis) tetapi sebaliknya hanya melarang analog objek dari subtipe awalan.) Saya bisa membayangkan kita memutar ulang utas itu di sini.

Tanda kurung adalah kuncinya di sini. Saya tidak yakin apa sebenarnya yang ada dalam pikiran mereka di utas itu, tetapi sepertinya itu bukan hal yang sama. Jika tidak, pernyataan seperti "diasumsikan bahwa tipe T & U selalu dapat ditetapkan ke T , tetapi ini gagal jika T adalah tipe yang tepat" tidak akan masuk akal (ini tidak' t gagal, karena T & U tidak valid atau terbawah). Pertanyaan lainnya terutama tentang pragmatik, yaitu, di mana seorang programmer ingin menggunakannya (untuk objek), yang tidak berlaku dalam kasus kami.

Untuk sistem tipe tingkat rendah, bukankah tipe yang tepat merupakan bahan penting bahkan di beberapa makalah Anda sendiri?

Sebagai contoh bagaimana masalah semacam ini dapat terjadi untuk WebAssembly, misalkan kami tidak menunda subtipe. Jenis ref.null akan menjadi nullref yang tepat menggunakan jenis yang tepat. Tetapi nullref yang tepat tidak akan menjadi subtipe dari anyref yang tepat.

Tidak ada perselisihan di sini. Tidak memiliki subtipe adalah tujuan dari tipe yang tepat.

Faktanya, menurut semantik biasa dari tipe eksak, kemungkinan tidak ada nilai yang menjadi milik anyref yang tepat karena kemungkinan tidak ada tipe run-time nilai yang persis anyref.

Benar, kombinasi (exact anyref) bukanlah tipe yang berguna, mengingat bahwa satu-satunya tujuan anyref adalah menjadi supertipe. Tapi mengapa itu menjadi masalah?

Ini akan membuat call_indirect benar-benar tidak dapat digunakan untuk anyrefs.

Apakah Anda yakin bahwa Anda tidak membingungkan level sekarang? Tipe fungsi (exact (func ... -> anyref)) sangat berguna. Hanya saja tidak kompatibel dengan tipe, katakanlah, (func ... -> (ref $T)) . Artinya, exact mencegah subtipe non-sepele pada tipe fungsi. Tapi itulah intinya!

Mungkin Anda mencampur (exact (func ... -> anyref)) dengan (func ... -> exact anyref) ? Ini adalah tipe yang tidak berhubungan.

Saran tipe persis Anda hanya mengatasi masalah dengan subtipe, tetapi kami menetapkan di atas bahwa call_indirect memiliki masalah bahkan tanpa subtipe apa pun.

Anda entah bagaimana berasumsi bahwa Anda akan dapat mengekspor tipe tanpa definisinya sebagai sarana untuk mendefinisikan tipe data abstrak. Jelas, pendekatan itu tidak berfungsi dengan adanya gips tipe dinamis (call_indirect atau lainnya). Itu sebabnya saya terus mengatakan bahwa kita membutuhkan abstraksi tipe gaya baru, bukan abstraksi tipe gaya ML.

Pemahaman saya adalah bahwa kasus penggunaan utama call_indirect adalah untuk mendukung pointer fungsi C/C++

Ya, tapi itu bukan satu-satunya kasus penggunaan ref.func , yang saya maksud, karena Anda memasukkannya ke dalam batasan yang Anda sarankan (mungkin tidak perlu begitu?). Secara khusus, akan ada call_ref , yang tidak melibatkan pemeriksaan tipe.

Anda entah bagaimana berasumsi bahwa Anda akan dapat mengekspor tipe tanpa definisinya sebagai sarana untuk mendefinisikan tipe data abstrak. Jelas, pendekatan itu tidak berfungsi dengan adanya gips tipe dinamis (call_indirect atau lainnya). Itu sebabnya saya terus mengatakan bahwa kita membutuhkan abstraksi tipe gaya baru, bukan abstraksi tipe gaya ML.

Oke, jadi Anda sepertinya setuju bahwa tipe yang tepat tidak melakukan apa pun untuk mengatasi masalah dengan call_indirect dan ketik impor. Tetapi Anda juga mengatakan bahwa tidak ada gunanya mengatasi masalah itu karena itu akan menjadi masalah karena run-time cast. Ada cara mudah untuk mencegah masalah itu: jangan izinkan orang melakukan gips run-time pada tipe abstrak (kecuali tipe abstrak secara eksplisit mengatakan itu bisa ditransmisikan). Bagaimanapun, ini adalah tipe buram, jadi kita tidak boleh berasumsi bahwa itu menunjukkan struktur yang diperlukan untuk melakukan gips. Jadi, bahkan jika ada kemungkinan bahwa tipe yang tepat mengatasi masalah subtipe, masih terlalu dini untuk mengabaikan separuh masalah lainnya.

Seperti yang saya katakan, setiap solusi memiliki pengorbanan. Anda tampaknya menganggap bahwa solusi Anda hanya memiliki pengorbanan yang telah Anda identifikasi sendiri, dan Anda tampaknya menganggap bahwa CG akan lebih memilih solusi Anda daripada yang lain. Saya juga punya solusi potensial untuk masalah ini. Ini menjamin pemeriksaan waktu konstan, didasarkan pada teknologi yang sudah digunakan di mesin virtual, mengatasi semua masalah di sini (saya percaya), tidak memerlukan penambahan jenis baru, dan benar-benar menambahkan fungsionalitas tambahan ke WebAssembly dengan aplikasi yang dikenal. Namun, saya tidak berasumsi bahwa itu berfungsi seperti yang saya harapkan dan bahwa saya tidak mengabaikan beberapa kekurangan karena Anda dan orang lain tidak memiliki kesempatan untuk memeriksanya. Saya juga tidak berasumsi bahwa CG akan lebih memilih pengorbanannya daripada opsi alternatif. Sebaliknya, saya mencoba mencari tahu apa yang dapat kami lakukan untuk memberi kami waktu untuk menganalisis opsi sehingga CG, bukan hanya saya, dapat menjadi orang yang membuat keputusan berdasarkan informasi tentang topik lintas sektoral ini.

Secara khusus, akan ada call_ref , yang tidak melibatkan pemeriksaan tipe.

Kata kunci dalam kalimat Anda adalah kemauan . Saya menyadari bahwa ada aplikasi dari call_indirect dengan jenis non-numerik bahwa orang akan ingin telah mendukung. Dan saya berharap kami akan membuat desain yang mendukung fungsi tersebut dan mengatasi masalah di atas. Namun, seperti yang saya katakan, idealnya kita dapat memiliki waktu untuk mengembangkan desain itu sehingga kita tidak dengan cepat mengirimkan fitur dengan implikasi lintas sektoral sebelum kita memiliki kesempatan untuk menyelidiki implikasi tersebut. Jadi pertanyaan saya adalah apakah ada program utama yang membutuhkan fungsionalitas itu sekarang . Jika ada, tidak perlu berhipotesis; cukup tunjuk beberapa dan ilustrasikan bagaimana mereka saat ini mengandalkan fungsi ini.

Anda entah bagaimana berasumsi bahwa Anda akan dapat mengekspor tipe tanpa definisinya sebagai sarana untuk mendefinisikan tipe data abstrak. Jelas, pendekatan itu tidak berfungsi dengan adanya gips tipe dinamis (call_indirect atau lainnya). Itu sebabnya saya terus mengatakan bahwa kita membutuhkan abstraksi tipe gaya baru, bukan abstraksi tipe gaya ML.

Ini sepertinya masalah mendasar bagi saya. Apakah mengaktifkan kerahasiaan definisi jenis yang diekspor merupakan tujuan dari proposal impor jenis? Saya menyimpulkan dari utas ini bahwa @RossTate berpikir itu harus menjadi tujuan dan @rossberg berpikir saat ini bukan tujuan. Mari kita diskusikan dan sepakati pertanyaan ini sebelum membahas solusi sehingga kita semua bisa bekerja dari asumsi yang sama.

@RossTate :

Oke, jadi Anda sepertinya setuju bahwa tipe yang tepat tidak melakukan apa pun untuk mengatasi masalah dengan call_indirect dan ketik impor.

Ya, jika maksud Anda pertanyaan tentang cara menambahkan fitur untuk mendefinisikan tipe data abstrak. Ada beberapa cara bagaimana abstraksi tipe dapat bekerja secara konsisten, tetapi fitur seperti itu lebih jauh.

Kata kunci dalam kalimat Anda adalah kemauan. Saya sepenuhnya menyadari bahwa ada aplikasi call_indirect dengan tipe non-numerik yang ingin didukung orang.

Instruksi call_ref ada dalam proposal ref fungsi, jadi cukup dekat, dalam hal apa pun sebelum mekanisme tipe data abstrak potensial. Apakah Anda menyarankan agar kami menundanya sampai saat itu?

@tlively :

Apakah mengaktifkan kerahasiaan definisi jenis yang diekspor merupakan tujuan dari proposal impor jenis? Saya menyimpulkan dari utas ini bahwa @RossTate berpikir itu harus menjadi tujuan dan @rossberg berpikir saat ini bukan tujuan.

Ini adalah tujuan, tetapi mekanisme tipe data abstrak adalah fitur yang terpisah. Dan mekanisme seperti itu harus dirancang sedemikian rupa sehingga tidak mempengaruhi desain impor. Jika ya, maka kita akan melakukannya dengan sangat salah -- abstraksi harus dipastikan di situs definisi, bukan situs penggunaan. Untungnya, ini bukan ilmu roket, dan ruang desainnya cukup terekspor.

Terima kasih, @rossberg , itu masuk akal. Menambahkan primitif abstraksi dalam proposal tindak lanjut setelah jenis impor dan ekspor terdengar baik bagi saya, tetapi akan sangat bagus jika kita dapat menuliskan detail tentang bagaimana kita berencana untuk melakukannya di suatu tempat segera. Desain impor dan ekspor tipe membatasi dan menginformasikan desain impor dan ekspor tipe abstrak, jadi penting bagi kita untuk memiliki gagasan yang baik tentang bagaimana abstraksi akan bekerja sebelum kita menyelesaikan desain awal.

Selain merinci rencana itu, karena masalah dengan call_indirect ini menunjukkan bahwa itu memengaruhi keputusan yang mendesak, dapatkah Anda menjelaskan mengapa Anda tampaknya menolak saran saya bahwa tipe abstrak tidak boleh dilemparkan (kecuali secara eksplisit dibatasi untuk dapat dilemparkan? )? Mereka buram, sehingga saran tampaknya sejalan dengan praktik umum tipe abstrak.

@tlively , ya, setuju. Ditambah berbagai hal lain yang ingin saya tulis untuk sementara waktu. Akan dilakukan setelah saya mengatasi semua dampak dari #69 . ;)

@RossTate , karena itu akan membuat tipe data abstrak tidak kompatibel dengan gips. Hanya karena saya ingin mencegah orang lain melihat _through_ tipe abstrak, saya tidak selalu ingin mencegah mereka (atau saya sendiri) dari casting _to_ tipe abstrak. Menciptakan dikotomi palsu seperti itu akan mematahkan kasus penggunaan gips sentral. Misalnya, tentu saja saya ingin dapat meneruskan nilai tipe abstrak ke fungsi polimorfik.

@rossberg Bisakah Anda mengklarifikasi apa kasus penggunaan utama yang Anda pikirkan? Tebakan terbaik saya dalam menafsirkan contoh Anda dapat dipecahkan secara sepele, tetapi mungkin maksud Anda lain.

@RossTate , pertimbangkan fungsi polimorfik. Singkat dari Wasm-generics, ketika mengkompilasinya menggunakan gips naik/turun dari anyref, maka seharusnya dimungkinkan untuk menggunakannya dengan nilai tipe abstrak seperti yang lain, tanpa pembungkus ekstra ke objek lain. Anda biasanya ingin dapat memperlakukan nilai tipe abstrak seperti yang lain.

Oke, mari kita pertimbangkan fungsi polimorfik, dan misalkan tipe yang diimpor adalah Handle :

  1. Java memiliki fungsi polimorfik. Fungsi polimorfiknya mengharapkan semua nilai (referensi Java) menjadi objek. Secara khusus, mereka harus memiliki v-tabel. Modul Java yang menggunakan Handle kemungkinan akan menentukan kelas Java CHandle mungkin mengimplementasikan antarmuka. Instance kelas ini akan memiliki anggota (tingkat wasm) tipe Handle dan v-tabel yang menyediakan pointer fungsi ke implementasi berbagai metode kelas dan antarmuka. Ketika diberikan ke fungsi polimorfik tingkat permukaan, yang pada tingkat wasm hanyalah fungsi pada objek, modul dapat menggunakan mekanisme yang sama yang digunakan untuk mentransmisikan ke kelas lain untuk mentransmisikan CHandle .
  2. OCaml memiliki fungsi polimorfik. Fungsi polimorfiknya mengharapkan semua nilai OCaml untuk mendukung kesetaraan fisik. Karena wasm tidak dapat mempertimbangkan keamanan tipe OCaml, fungsi polimorfiknya juga mungkin perlu banyak menggunakan gips. Struktur pengecoran khusus kemungkinan akan membuat ini lebih efisien. Untuk salah satu dari alasan ini, modul OCaml kemungkinan akan menentukan tipe data aljabar atau tipe rekaman THandle yang cocok dengan norma-norma ini dan memiliki anggota (tingkat wasm) tipe Handle . Fungsi polimorfiknya kemudian akan memberikan nilai OCaml ke THandle seperti yang mereka lakukan pada tipe data aljabar atau tipe rekaman lainnya.

Dengan kata lain, karena modul bergantung pada norma tentang bagaimana nilai tingkat permukaan direpresentasikan untuk mengimplementasikan hal-hal seperti fungsi polimorfik, dan tipe impor abstrak seperti Handle tidak memenuhi norma ini, pembungkusan nilai tidak dapat dihindari. Ini adalah alasan yang sama salah satu aplikasi asli untuk anyref digantikan oleh Jenis Antarmuka. Dan kami mengembangkan studi kasus yang menunjukkan bahwa anyref tidak diperlukan, bahkan tidak cocok, untuk mendukung fungsi polimorfik.

Di sisi lain, Anda telah menunjukkan bahwa anyref castable dapat digunakan untuk menghindari mekanisme abstraksi statis. Rencana mekanisme abstraksi yang Anda singgung adalah upaya untuk menambal masalah ini melalui mekanisme abstraksi dinamis. Tetapi ada sejumlah masalah dengan mekanisme abstraksi dinamis. Misalnya, seseorang tidak dapat mengekspor tipe i31ref sebagai tipe abstrak Handle tanpa risiko modul lain menggunakan anyref dan casting untuk memalsukan pegangan (mis. ke kemampuan). Alih-alih, kita harus melewati rintangan dan overhead tambahan yang tidak perlu jika kita hanya memastikan abstraksi statis standar.

Juga, sekarang (saya pikir) saya lebih memahami bagaimana Anda bermaksud menggunakan tipe yang tepat, saya menyadari bahwa niat Anda tidak membahas dua masalah utama yang saya perhatikan dengan call_indirect dan subtipe:

  1. Itu tidak membantu membuat call_indirect menghormati subtipe (yang saya pikir Anda sudah katakan secara eksplisit)
  2. Itu tidak mencegah call_indirect digunakan untuk menggunakan fungsi yang diekspor dengan tanda tangan yang ditentukan daripada tanda tangan yang diekspor.

Jadi ini bukan masalah sepele untuk dipecahkan. Itu sebabnya, mengingat keterbatasan waktu, saya lebih suka fokus mengevaluasi bagaimana memberi kami waktu untuk menyelesaikannya dengan benar. Saya tidak berpikir perlu untuk terlebih dahulu berdiskusi tentang apakah anyref layak untuk membuang abstraksi statis. Itulah jenis diskusi besar yang saya harapkan untuk dihindari agar tidak menunda hal-hal lebih lanjut.

Di sisi lain, Anda telah menunjukkan bahwa anyref castable dapat digunakan untuk menghindari mekanisme abstraksi statis.

Abstraksi tipe statis tidak cukup dalam bahasa dengan gips tipe dinamis. Karena abstraksi statis bergantung pada parametrik, dan gips memecahkannya. Tidak ada yang baru tentang itu, makalah telah ditulis tentang itu. Mekanisme abstraksi lain diperlukan dalam konteks seperti itu.

Mencoba mengatasinya dengan membatasi penggunaan tipe abstrak mengalahkan tujuannya. Pertimbangkan kasus penggunaan WASI. Seharusnya tidak masalah apakah modul WASI dan jenis apa pun yang diekspornya diimplementasikan oleh host atau di Wasm. Jika Anda secara sewenang-wenang membatasi tipe abstrak yang ditentukan pengguna, maka implementasi Wasm tidak lagi dapat dipertukarkan dengan implementasi host secara umum.

  1. Itu tidak membantu membuat call_indirect menghormati subtipe (yang saya pikir sudah Anda katakan secara eksplisit)

Hah? Ini adalah bagian dari aturan subtipe, begitu juga menurut definisi.

  1. Itu tidak mencegah call_indirect digunakan untuk menggunakan fungsi yang diekspor dengan tanda tangan yang ditentukan daripada tanda tangan yang diekspor.

Saya tidak mengatakan itu. Saya mengatakan bahwa ini bukan masalah dengan call_indirect itu sendiri, tetapi pertanyaan tentang memilih mekanisme abstraksi tipe yang sesuai untuk bahasa dengan gips.

Selain itu, tidak ada alasan kuat mengapa kompilasi OCaml (atau bahasa serupa lainnya) memerlukan pengenalan tipe varian. Bahkan jika itu bisa sedikit lebih cepat secara teori (yang saya ragu akan terjadi pada mesin generasi saat ini, kemungkinan besar sebaliknya), tipe varian adalah komplikasi signifikan yang seharusnya tidak diperlukan untuk MVP. Saya tidak cukup berbagi selera Anda untuk kompleksitas prematur. ;)

Persamaan kembali pada fungsi: ada bahasa, seperti Haskell atau SML, yang tidak mendukungnya, jadi mungkin mendapat manfaat langsung dari referensi func. OCaml melempar untuk kesetaraan struktural dan secara eksplisit memiliki perilaku yang ditentukan implementasi untuk yang fisik. Itu dibiarkan terbuka apakah itu memungkinkan selalu mengembalikan false atau melempar untuk fungsi, tetapi keduanya mungkin cukup dalam praktiknya, dan perlu ditelusuri sebelum melakukan pembungkus ekstra yang mahal.

[Sebagai komentar meta, saya akan sangat menghargai jika Anda mengurangi kuliah Anda dan mungkin mempertimbangkan gagasan bahwa ini adalah dunia di mana, mungkin, kumpulan orang yang kompeten tidak tunggal dan jejak otak kadang-kadang telah diterapkan sebelumnya.]

Sebagai komentar meta, saya akan sangat menghargai jika Anda mengurangi kuliah Anda

Mendengar.

dan mungkin mempertimbangkan gagasan bahwa ini adalah dunia di mana, mungkin, kumpulan orang yang kompeten tidak tunggal dan jejak otak kadang-kadang telah diterapkan sebelumnya.

Saran saya di sini didasarkan pada konsultasi dengan banyak ahli.

Abstraksi tipe statis tidak cukup dalam bahasa dengan gips tipe dinamis. Karena abstraksi statis bergantung pada parametrik, dan gips memecahkannya. Tidak ada yang baru tentang itu, makalah telah ditulis tentang itu. Mekanisme abstraksi lain diperlukan dalam konteks seperti itu.

Para ahli yang telah saya konsultasikan dengan termasuk penulis dari beberapa makalah tersebut.

Sekarang, sebagai upaya untuk memeriksa bahwa saya telah mensintesis saran mereka dengan benar, saya baru saja mengirim email kepada penulis lain dari beberapa makalah tersebut, yang belum pernah saya bahas topik ini sebelumnya. Inilah yang saya tanyakan:

Misalkan saya memiliki fungsi polimorfik f(...). Bahasa yang saya ketik memiliki subtipe (subsumptif) dan casting eksplisit. Namun, cast dari t1 ke t2 hanya memeriksa apakah t2 adalah subtipe dari t1. Misalkan variabel tipe seperti X secara default tidak memiliki subtipe atau supertipe (selain diri mereka sendiri tentu saja). Apakah Anda mengharapkan f menjadi parametrik relasional terhadap X?

Inilah tanggapan mereka:

Ya, saya pikir ini akan menjadi parametrik karena satu-satunya kemampuan yang diberikan ini kepada Anda adalah menulis gips pada X yang setara dengan fungsi identitas, yang sudah bersifat parametrik relasional.

Ini sesuai dengan saran saya. Sekarang, tentu saja, ini adalah penyederhanaan masalah yang dihadapi, tetapi kami telah berupaya untuk menyelidiki masalah secara lebih spesifik ke WebAssembly, dan sejauh ini eksplorasi kami menunjukkan bahwa harapan ini terus berlanjut bahkan pada skala WebAssembly kecuali untuk call_indirect , maka masalah ini.

Perhatikan bahwa teorema yang Anda maksud berlaku untuk bahasa di mana semua nilai dapat dicetak. Pengamatan ini adalah di mana kami mendapat ide untuk membatasi castability.

Pertimbangkan kasus penggunaan WASI.

Saya tidak mengerti klaim yang Anda buat. Kami telah mempertimbangkan kasus penggunaan WASI. Oleh kami, saya menyertakan banyak pakar keamanan dan bahkan keamanan berbasis kemampuan khusus.

Sebagai komentar meta, saya akan sangat menghargai tidak perlu mengajukan banding ke otoritas atau CG agar saran saya didengar. Saya menyarankan bahwa membatasi gips akan memungkinkan memastikan parametrik statis bahkan di hadapan gips. Anda segera mengabaikan saran itu, mengajukan banding ke surat-surat sebelumnya untuk membenarkan pemecatan itu. Namun ketika saya menawarkan saran yang sama kepada penulis makalah tersebut, mereka segera sampai pada kesimpulan yang sama seperti yang saya lakukan dan seperti yang Anda bisa. Sebelum itu, saya menyarankan bahwa mengevaluasi solusi potensial akan menjadi proses yang panjang. Anda mengabaikan saran itu, bersikeras bahwa Anda (sendirian) telah memecahkan masalah, menarik kami berdua ke dalam percakapan panjang ini. Sangat sulit untuk membuat kemajuan, dan untuk menghindari frustrasi, ketika saran seseorang berulang kali ditolak begitu saja. (Saya harus mengklarifikasi bahwa saya tidak mencoba untuk mengabaikan saran Anda sebagai solusi yang mungkin di sini; Saya mencoba menunjukkan bahwa itu bukan satu-satunya solusi dan karenanya harus dievaluasi bersama dengan berbagai solusi lainnya.)

Saya pikir memiliki desain terperinci yang dipaku dan diteliti yang membahas masalah yang diangkat dalam masalah ini adalah penting dan tepat waktu: Saya sebenarnya tidak berpikir tipe abstrak harus dianggap sebagai fitur yang lebih jauh; WASI membutuhkan mereka sekarang-ish.

Saya juga memiliki harapan bahwa exact + newtype dapat mengatasi masalah tersebut, tetapi saya setuju bahwa kita tidak bisa begitu saja mempertaruhkan pertanian pada firasat ini pada saat ini dengan berkomitmen sebelum waktunya pada desain ketika kami (segera) mengirimkan jenis referensi. Kita perlu waktu untuk berdiskusi dengan baik tentang hal itu.

Karena itu, saya tidak melihat bahaya dengan mengizinkan externref di call_indirect tanda tangan dalam proposal tipe referensi. Ya, jika sebuah modul mengekspor nilai externref (sebagai const global atau mengembalikannya dari suatu fungsi ...), kami belum menentukan apakah kami dapat menurunkan externref . Tapi call_indirect tidak merendahkan externref ; itu menurunkan funcref , dan externref tidak berbeda dengan peran i32 wrt funcref-type-equality check. Jadi, dengan tidak adanya impor tipe, ekspor tipe, dan subtipe yang dimainkan di call_indirect , saya tidak melihat bagaimana kami berkomitmen pada pilihan desain baru yang belum kami komitmenkan di MVP .

Jika tidak ada bahaya, mungkin kita bisa mengalihkan diskusi yang intens ini ke diskusi yang kurang intens dalam proposal Type Imports (di mana saya masih berpikir kita harus menyertakan dukungan tipe abstrak yang tepat)?

Tentu. Saya pikir itu ide yang baik untuk memeriksa apakah ada bahaya atau tidak.

Mengenai WASI, desainnya masih sangat berubah-ubah, tetapi satu opsi yang tampaknya masih layak adalah menggunakan sesuatu seperti i31ref untuk "pegangannya", katakanlah karena tidak memerlukan alokasi memori dinamis. WASI dapat memutuskan opsi lain, tetapi intinya adalah tidak ada yang tahu saat ini, dan alangkah baiknya jika keputusan yang dibuat sekarang tidak memengaruhi keputusan tersebut di masa mendatang.

Saat ini, externref adalah satu-satunya tipe abstrak yang tersedia, sehingga host berbasis WASI akan menginisiasi externref dengan i31ref (atau "pegangan" WASI apa pun). Tetapi pemahaman saya adalah bahwa WASI ingin memindahkan implementasinya ke WebAssembly sebanyak mungkin untuk mengurangi kode yang bergantung pada host. Untuk memfasilitasi ini, pada titik tertentu sistem WASI mungkin ingin memperlakukan externref sama seperti jenis impor lainnya dan menginstansiasinya dengan jenis Handle abstrak WASI yang diekspor. Tetapi jika Handle adalah i31ref , maka implementasi call_indirect diperlukan untuk memungkinkannya bekerja melintasi batas modul juga dapat digunakan untuk membiarkan orang memalsukan pegangan melalui externref .

Jadi salah satu pertanyaan saya, yang sekarang saya perhatikan tidak dinyatakan dengan jelas di posting asli saya, apakah orang ingin externref menjadi instantiable seperti impor tipe abstrak lainnya?

Jadi salah satu pertanyaan saya, yang sekarang saya perhatikan tidak dinyatakan dengan jelas di posting asli saya, apakah orang ingin externref menjadi instantiable seperti impor tipe abstrak lainnya?

Terima kasih telah mengajukan pertanyaan ini secara eksplisit. FWIW, saya tidak pernah mengerti externref dapat dipakai dari dalam modul WebAssembly. Itu menyiratkan partisipasi tuan rumah dalam virtualisasi jika WASI ingin menggunakan externref sebagai pegangan, tetapi itu menurut saya baik-baik saja, atau setidaknya tampaknya diskusi yang dapat dipisahkan.

Hmm, coba saya lihat apakah saya bisa mengklarifikasi. Saya menduga Anda sudah bergabung dengan banyak hal berikut, tetapi lebih mudah bagi saya untuk memulai dari awal.

Dari perspektif modul wasm, externref tidak berarti referensi host. Ini hanya tipe buram yang tidak diketahui modul. Sebaliknya, konvensi sekitar externref yang menafsirkannya sebagai referensi host. Misalnya, konvensi modul yang menggunakan externref untuk berinteraksi dengan DOM akan terlihat jelas dalam fungsi yang melibatkan externref yang diimpor modul, seperti parentNode : [externref] -> [externref] dan childNode : [externref, i32] -> [externref] . Lingkungan modul, seperti host itu sendiri, adalah yang sebenarnya memberikan interpretasi externref sebagai referensi host, dan menyediakan implementasi metode yang diimpor yang menguatkan interpretasi itu.

Namun, lingkungan modul tidak harus menjadi host dan externref tidak harus menjadi referensi host. Lingkungan dapat berupa modul lain yang menyediakan fungsionalitas untuk beberapa jenis yang terlihat seperti referensi host yang menunjukkan konvensi yang diharapkan. Misalkan modul E adalah lingkungan modul M, dan modul M mengimpor parentNode dan childNode seperti di atas. Katakanlah E ingin menggunakan modul M tetapi ingin membatasi akses M ke DOM, katakanlah karena E memiliki kepercayaan terbatas pada M atau karena E ingin mengikat semua bug yang mungkin dimiliki M dan mengetahui bahwa kebutuhan M tidak boleh melebihi batasan ini. Apa yang bisa dilakukan E adalah membuat instance M dengan "MonitoredRef" sebagai externref M. Katakanlah, khususnya, E ingin memberikan node DOM M tetapi memastikan bahwa M tidak berjalan lebih tinggi ke atas pohon DOM. Kemudian MonitoredRef E dapat secara khusus ref (struct externref externref) , di mana externref (dari perspektif E) adalah simpul DOM tempat M beroperasi, tetapi externref adalah nenek moyang dari simpul yang M tidak boleh lewati. E kemudian dapat membuat instance parentNode M sedemikian rupa sehingga salah jika kedua referensi ini sama. E sendiri akan mengimpor fungsi parentNode dan childNode miliknya sendiri, membuat E efektif sebagai monitor run-time interaksi DOM.

Mudah-mudahan itu cukup konkret untuk melukis gambar yang tepat, sementara tidak terlalu konkret untuk tersesat dalam detail. Jelas ada sejumlah pola seperti ini. Jadi saya kira cara lain untuk mengungkapkan pertanyaannya adalah, apakah kita ingin externref hanya mewakili referensi Host dengan tepat?

Satu-satunya bagian yang terdengar meragukan bagi saya adalah "apa yang dapat dilakukan E adalah membuat instance M dengan "MonitoredRef" sebagai M's externref ." Saya tidak mendapat kesan bahwa ada rencana untuk mengizinkan hal-hal abstrak muncul sebagai externref di modul lain. Pemahaman saya adalah bahwa externref bukanlah alat abstraksi sama sekali.

Saya juga tidak tahu rencana semacam itu; Saya juga tidak tahu apakah ada yang mempertimbangkan opsi ini. Yaitu, haruskah externref menjadi tipe "primitif", misalnya seperti i32 , atau tipe "instantiable", misalnya seperti jenis yang diimpor?

Dalam posting asli saya, saya menunjukkan bahwa salah satu cara dapat dikelola. Pengorbanan untuk menggunakan interpretasi "primitif" adalah bahwa externref secara substansial kurang berguna/dapat dikomposisi daripada jenis yang diimpor, karena yang terakhir akan mendukung kasus penggunaan externref serta pola di atas. Dengan demikian, "primitif" externref tampaknya akan menjadi sisa—hanya ada untuk kompatibilitas mundur. Tapi itu sepertinya tidak terlalu bermasalah, hanya gangguan. Masalah terbesar yang dapat saya lihat adalah, seperti perilaku baik call_indirect pada tipe numerik berhasil karena mereka tidak memiliki supertipe, perilaku baik call_indirect mungkin berakhir tergantung pada externref tidak memiliki supertipe juga.

Ah hah, ya, ini menjelaskan perbedaan pemahaman: Saya setuju dengan @tlively bahwa externref sama sekali tidak abstrak dan tidak ada gagasan "instantiating externref dengan tipe", dan saya pikir kita bisa merasa cukup percaya diri tentang ini ke depan. (Karena externref adalah tipe primitif, sebagai lawan dari parameter tipe yang dideklarasikan secara eksplisit, tidak jelas bagaimana seseorang bahkan dapat mencoba untuk membuat instance berdasarkan per-modul.)

Dengan tidak adanya downcasts, fakta ini membuat wasm hampir tidak berguna untuk menerapkan/virtualisasi WASI API itulah sebabnya rencana WASI adalah untuk transisi dari i32 menangani langsung ke Type Imports (dan mengapa saya mengajukan type-imports /#6 , b/c kita perlu sedikit lagi).

Karena externref adalah tipe primitif, sebagai lawan dari parameter tipe yang dideklarasikan secara eksplisit, tidak jelas bagaimana seseorang bahkan dapat mencoba membuat instance berdasarkan per-modul.

Saat kita menambahkan impor tipe, kita dapat memperlakukan modul tanpa impor tipe tetapi dengan externref memiliki import type externref di bagian atas. Semuanya akan mengetik-periksa sama karena, tidak seperti tipe primitif lainnya, externref tidak memiliki operasi primitif terkait (selain memiliki nilai default). Tetapi dengan impor implisit itu, sekarang kita dapat melakukan hal-hal seperti virtualisasi, sandboxing, dan pemantauan run-time.

Tapi sebelum bolak-balik tentang itu, saya pikir itu akan membantu untuk mengukur apakah kita semua berada di halaman yang sama tentang sesuatu. Beri tahu saya jika Anda setuju atau tidak setuju dengan pernyataan berikut dan alasannya: "Setelah jenis impor tersedia, modul tidak memiliki alasan untuk menggunakan externref dan lebih dapat digunakan kembali/dikomposisi jika mereka menggunakan impor jenis sebagai gantinya."

Beri tahu saya jika Anda setuju atau tidak setuju dengan pernyataan berikut dan alasannya: "Setelah jenis impor tersedia, modul tidak memiliki alasan untuk menggunakan externref dan lebih dapat digunakan kembali/dikomposisi jika mereka menggunakan impor jenis sebagai gantinya."

Saya setuju dengan pernyataan ini dalam abstrak. Dalam praktiknya saya pikir externref akan tetap umum dalam konteks web untuk merujuk ke objek JS eksternal karena tidak memerlukan konfigurasi tambahan pada waktu instantiasi. Tapi itu hanya prediksi dan saya tidak keberatan jika ternyata saya salah dan semua orang beralih menggunakan impor tipe. Nilai dari externref adalah bahwa kita dapat memilikinya lebih cepat daripada mekanisme yang lebih kaya seperti jenis impor. Saya lebih suka menjaga externref tetap sederhana dan melihatnya tidak digunakan daripada dengan canggung membuatnya menjadi sesuatu yang lebih kuat di kemudian hari ketika ada alternatif yang lebih elegan.

@tlively ,

FWIW, saya tidak pernah mengerti externref menjadi instantiable dari dalam modul WebAssembly.

Benar, idenya adalah externref adalah tipe pointer asing "primitif". Untuk mengabstraksi detail implementasi dari tipe referensi, Anda memerlukan sesuatu yang lain: sesuatu seperti anyref atau impor tipe.

@lukewagner , saya akan ikut memperluas cakupan proposal jenis impor, jika itu lebih disukai. Tapi trade-off adalah bahwa proposal akan memakan waktu lebih lama. Saya mendapat kesan bahwa impor tipe dapat berguna tanpa tipe data abstrak dalam bahasa, dan karenanya diinginkan lebih cepat daripada nanti. Ini berarti Anda sudah dapat mengekspresikan dan _menggunakan_ antarmuka WASI, tetapi belum _mengimplementasikannya di Wasm. Tapi kedua cara baik-baik saja dengan saya.

@RossTate :

Para ahli yang telah saya konsultasikan dengan termasuk penulis dari beberapa makalah tersebut.

Bagus sekali. Kemudian saya berasumsi Anda telah memperhatikan bahwa Anda benar-benar adalah penulis beberapa makalah ini sendiri, jika Anda mencari otoritas yang lebih besar. :)

Inilah yang saya tanyakan:

Misalkan saya memiliki fungsi polimorfik f(...). Bahasa yang saya ketik memiliki subtipe (subsumptif) dan casting eksplisit. Namun, cast dari t1 ke t2 hanya memeriksa apakah t2 adalah subtipe dari t1. Misalkan variabel tipe seperti X secara default tidak memiliki subtipe atau supertipe (selain diri mereka sendiri tentu saja). Apakah Anda mengharapkan f menjadi parametrik relasional terhadap X?

Mendesah. Saya akan memberikan jawaban yang sama untuk pertanyaan spesifik itu. Tapi pertanyaan ini mewujudkan beberapa asumsi spesifik, misalnya tentang sifat gips, dan tentang perbedaan yang agak tidak biasa antara kuantifikasi terbatas dan tak terbatas yang jarang ada dalam bahasa pemrograman apapun. Dan saya kira itu karena suatu alasan.

Ketika saya mengatakan "abstraksi tipe statis tidak mencukupi" maka saya tidak bermaksud bahwa itu tidak _secara teknis_ mungkin (tentu saja), tetapi itu tidak _praktis_ memadai. Dalam praktiknya, Anda tidak ingin bifurkasi antara abstraksi tipe dan subtipe/castability (atau antara tipe parametrik dan non-parametrik), karena itu akan secara artifisial memecah komposisi berdasarkan gips.

Saya tidak mengerti klaim yang Anda buat.

Jika Anda menerima nilai tipe abstrak maka Anda mungkin masih ingin melupakan tipe persisnya, misalnya memasukkannya ke dalam semacam gabungan, dan kemudian memulihkannya melalui downcast. Anda mungkin ingin melakukannya untuk alasan yang sama seperti yang Anda inginkan untuk jenis referensi lainnya. Abstraksi tipe tidak boleh menghalangi pola penggunaan tertentu yang valid dengan tipe reguler dari jenis yang sama.

Jawaban Anda sepertinya: jadi apa, bungkus semuanya menjadi tipe tambahan di situs penggunaan masing-masing, misalnya ke dalam varian. Tapi itu bisa menyiratkan overhead pembungkus/pembukaan yang substansial, itu membutuhkan fitur sistem tipe yang lebih kompleks, dan lebih rumit untuk digunakan.

Saya pikir inilah yang menyebabkan beberapa ketidaksepakatan kami: apakah MVP harus mendukung penyatuan tipe referensi, atau apakah itu harus memerlukan pengenalan dan pengkodean dengan tipe varian eksplisit. Baik atau buruk, serikat pekerja adalah kecocokan alami untuk antarmuka tumpukan mesin biasa, dan mereka mudah dan murah untuk didukung saat ini. Varian tidak begitu banyak, mereka adalah pendekatan yang jauh lebih teliti yang kemungkinan akan menyebabkan overhead ekstra dan kinerja yang kurang dapat diprediksi, setidaknya di mesin yang ada. Dan saya mengatakan bahwa sebagai orang sistem tipe yang lebih memilih varian daripada serikat pekerja dalam keadaan lain, seperti bahasa yang dihadapi pengguna. ;)

Sebagai komentar meta, saya akan sangat menghargai tidak perlu mengajukan banding ke otoritas atau CG agar saran saya didengar.

Perkenankan saya menyarankan agar percakapan tentang berbagai proposal dapat berjalan lebih baik jika dimulai dengan _menanyakan_ masing-masing juara tentang hal-hal yang tidak jelas, misalnya alasan spesifik atau rencana masa depan (yang tidak selalu jelas atau belum ditulis), sebelum _dengan asumsi_ tidak adanya jawaban dan membuat pernyataan dan saran yang luas berdasarkan asumsi ini?

Bagus sekali. Kemudian saya berasumsi Anda telah memperhatikan bahwa Anda benar-benar adalah penulis beberapa makalah ini sendiri, jika Anda mencari otoritas yang lebih besar. :)

Ya, yang membuatnya sangat bermasalah ketika Anda menyarankan bahwa ada makalah yang mengklaim bahwa saran saya tidak berhasil, meskipun Anda tahu bahwa saran saya secara khusus membahas kondisi klaim tersebut dibuat.

Dalam praktiknya, Anda tidak ingin bifurkasi antara abstraksi tipe dan subtipe/castability (atau antara tipe parametrik dan non-parametrik), karena itu akan secara artifisial memecah komposisi berdasarkan gips.

Ini adalah opini, bukan fakta (menjadikannya sesuatu yang sangat masuk akal bagi kita untuk tidak setuju). Saya akan mengatakan bahwa tidak ada bahasa rakitan yang diketik industri bahasa-agnostik untuk sistem multi-bahasa, dan karenanya tidak mungkin untuk membuat klaim tentang praktik. Ini adalah sesuatu yang layak untuk didiskusikan secara menyeluruh (terpisah). Untuk diskusi itu, ada baiknya Anda terlebih dahulu memberikan beberapa studi kasus terperinci sehingga CG dapat membandingkan pengorbanannya.

Perkenankan saya menyarankan agar percakapan tentang berbagai proposal dapat berjalan lebih baik jika dimulai dengan menanyakan masing-masing juara tentang hal-hal yang tidak jelas, misalnya alasan spesifik atau rencana masa depan (yang tidak selalu jelas atau belum tertulis), sebelum mengasumsikan tidak adanya jawaban dan membuat pernyataan dan saran yang luas berdasarkan asumsi ini?

WebAssembly/proposal-type-imports#4, WebAssembly/proposal-type-imports#6, dan WebAssembly/proposal-type-imports#7 masing-masing pada dasarnya meminta rincian lebih lanjut tentang rencana ini. Yang terakhir ini mengarahkan masalah ke GC, tetapi WebAssembly/gc#86 menunjukkan bahwa proposal GC saat ini sebenarnya tidak mendukung mekanisme abstraksi dinamis.

Pada level meta, kami diminta untuk mengesampingkan diskusi ini dan fokus pada topik yang ada. Saya menemukan tanggapan @tlively atas pertanyaan saya sangat membantu. Saya sebenarnya cukup tertarik untuk mendapatkan secara khusus pemikiran Anda tentang pertanyaan itu.

@RossTate :

Saya menemukan tanggapan @tlively atas pertanyaan saya sangat membantu. Saya sebenarnya cukup tertarik untuk mendapatkan secara khusus pemikiran Anda tentang pertanyaan itu.

Hm, saya pikir saya sudah mengomentarinya di atas . Atau maksudmu yang lain?

Tidak. Saya pikir komentar itu mungkin menyiratkan persetujuan dengan tanggapannya, tetapi saya ingin mengonfirmasi terlebih dahulu. Terima kasih!

@lukewagner , apa pendapat Anda?

Saya setuju dengan di atas bahwa externref akan selamanya menjadi tipe primitif dan tidak ditafsirkan ulang sebagai parameter tipe. Saya pikir, mengingat itu, tipe referensi baik untuk digunakan apa adanya.

Saya ingin menerima tawaran @rossberg untuk memperluas cakupan proposal Type Imports sehingga mencakup kemampuan wasm untuk mengimplementasikan tipe abstrak. Setelah kita dapat memahaminya, saya pikir itu akan membuka blokir diskusi lebih lanjut seputar referensi fungsi dan subtipe.

Luar biasa. Kemudian kita semua berada di halaman yang sama (dan saya juga berpikir @tlively memberikan ringkasan yang bagus tentang pengorbanan yang terlibat dan alasan untuk keputusan).

Jadi externref tidak akan dapat dibuat instan, dan modul yang mencari fleksibilitas ekstra dari impor tipe akan diharapkan untuk dikonversi menjadi impor tipe saat fitur dirilis. Terpikir oleh saya bahwa, untuk membuat transisi itu mulus, kita mungkin perlu membuatnya sehingga (beberapa?) jenis impor dipakai oleh externref secara default jika tidak ada instantiasi yang disediakan.

Dan saya juga ingin menerima tawaran untuk memperluas cakupan Jenis Impor. Banyak aplikasi utama dari impor tipe membutuhkan abstraksi, jadi bagi saya wajar jika abstraksi menjadi bagian dari proposal itu.

Sementara itu, meskipun kami telah menjawab pertanyaan mendesak tentang externref , apa yang harus dilakukan secara lebih umum tentang call_indirect masih belum terselesaikan, meskipun dengan beberapa diskusi yang berguna tentang bagaimana hal itu dapat diselesaikan, jadi saya masih akan membiarkan masalah terbuka.

Terima kasih!

Apakah halaman ini membantu?
0 / 5 - 0 peringkat

Masalah terkait

thysultan picture thysultan  ·  4Komentar

Artur-A picture Artur-A  ·  3Komentar

chicoxyzzy picture chicoxyzzy  ·  5Komentar

cretz picture cretz  ·  5Komentar

void4 picture void4  ·  5Komentar