Jenis Penghapusan Baik
Mari berpegang pada fakta
Banyak jawaban yang sejauh ini terlalu berkaitan dengan pengguna Twitter. Sangat membantu untuk tetap fokus pada pesan dan bukan pada pembawa pesan. Ada pesan yang cukup konsisten bahkan hanya dengan kutipan yang disebutkan sejauh ini:
Sangat lucu ketika pengguna Java mengeluh tentang penghapusan tipe, yang merupakan satu-satunya hal yang dilakukan Java dengan benar, sambil mengabaikan semua hal yang salah.
Saya mendapatkan keuntungan besar (misalnya parametrikitas) dan biaya nihil (dugaan biaya adalah batas imajinasi).
T baru adalah program yang rusak. Adalah isomorfik untuk klaim "semua proposisi benar". Saya tidak terlalu suka ini.
Sasaran: program yang masuk akal
Tweet ini mencerminkan perspektif yang tidak tertarik pada apakah kita dapat membuat mesin melakukannya sesuatu , tetapi lebih pada apakah kita dapat beralasan bahwa mesin akan melakukan sesuatu yang sebenarnya kita inginkan. Penalaran yang baik adalah buktinya. Bukti dapat ditentukan dalam notasi formal atau sesuatu yang kurang formal. Terlepas dari bahasa spesifikasinya, mereka harus jelas dan ketat. Spesifikasi informal bukan tidak mungkin untuk disusun dengan benar, tetapi sering kali cacat dalam pemrograman praktis. Kami berakhir dengan remediasi seperti tes otomatis dan eksplorasi untuk mengatasi masalah yang kami hadapi dengan penalaran informal. Ini bukan untuk mengatakan bahwa pengujian pada dasarnya adalah ide yang buruk, tetapi pengguna Twitter yang dikutip menunjukkan bahwa ada cara yang jauh lebih baik.
Jadi, tujuan kami adalah memiliki program yang benar yang dapat kami pertimbangkan dengan jelas dan tepat dengan cara yang sesuai dengan cara mesin akan menjalankan program tersebut. Namun, ini bukan satu-satunya tujuan. Kami juga ingin logika kami memiliki tingkat ekspresi yang tinggi. Misalnya, hanya ada begitu banyak yang bisa kita ekspresikan dengan logika proposisional. Sangat menyenangkan memiliki penghitungan universal (∀) dan eksistensial (∃) dari sesuatu seperti logika orde pertama.
Menggunakan sistem tipe untuk penalaran
Sasaran ini dapat ditangani dengan sangat baik oleh sistem tipe. Ini sangat jelas karena korespondensi Curry-Howard . Korespondensi ini sering diungkapkan dengan analogi berikut: tipe adalah program sebagaimana teorema untuk bukti.
Korespondensi ini cukup mendalam. Kita dapat mengambil ekspresi logis, dan menerjemahkannya melalui korespondensi ke tipe. Kemudian jika kita memiliki program dengan tanda tangan tipe yang sama yang dikompilasi, kita telah membuktikan bahwa ekspresi logis adalah benar secara universal (tautologi). Ini karena korespondensinya dua arah. Transformasi antara tipe / program dan dunia teorema / pembuktian bersifat mekanis, dan dalam banyak kasus dapat diotomatiskan.
Curry-Howard berperan dengan baik pada apa yang ingin kami lakukan dengan spesifikasi untuk suatu program.
Apakah sistem tipe berguna di Java?
Bahkan dengan pemahaman tentang Curry-Howard, beberapa orang merasa mudah untuk mengabaikan nilai sistem tipe, ketika itu
- sangat sulit untuk diajak bekerja sama
- sesuai (melalui Curry-Howard) dengan logika dengan ekspresi terbatas
- rusak (yang mendapat karakterisasi sistem sebagai "lemah" atau "kuat").
Mengenai poin pertama, mungkin IDE membuat sistem tipe Java cukup mudah untuk digunakan (itu sangat subjektif).
Mengenai poin kedua, Java hampir sesuai dengan logika orde pertama. Generik menggunakan sistem tipe yang setara dengan kuantifikasi universal. Sayangnya, karakter pengganti hanya memberi kita sebagian kecil dari kuantifikasi eksistensial. Tapi penghitungan universal adalah awal yang cukup bagus. Sangat menyenangkan dapat mengatakan bahwa fungsi List<A>
berfungsi secara universal untuk semua daftar yang memungkinkan karena A sama sekali tidak dibatasi. Ini mengarah pada apa yang dibicarakan pengguna Twitter sehubungan dengan "parametrikitas".
Makalah yang sering dikutip tentang parametrik adalah Teorema Philip Wadler gratis! . Yang menarik dari tulisan ini adalah hanya dari jenis tanda tangannya saja, kita bisa membuktikan beberapa invarian yang sangat menarik. Jika kita menulis pengujian otomatis untuk invarian ini, kita akan sangat membuang-buang waktu. Misalnya untuk List<A>
, dari type signature saja forflatten
<A> List<A> flatten(List<List<A>> nestedLists);
kita bisa beralasan itu
flatten(nestedList.map(l -> l.map(any_function)))
≡ flatten(nestList).map(any_function)
Itu adalah contoh sederhana, dan Anda mungkin dapat bernalar tentangnya secara informal, tetapi akan lebih bagus lagi ketika kita mendapatkan bukti seperti itu secara resmi secara gratis dari sistem tipe dan diperiksa oleh kompiler.
Tidak menghapus dapat menyebabkan penyalahgunaan
Dari perspektif implementasi bahasa, generik Java (yang sesuai dengan tipe universal) sangat berperan dalam parametrikitas yang digunakan untuk mendapatkan bukti tentang apa yang dilakukan program kami. Ini sampai pada masalah ketiga yang disebutkan. Semua perolehan bukti dan ketepatan ini membutuhkan sistem tipe suara yang diimplementasikan tanpa cacat. Java pasti memiliki beberapa fitur bahasa yang memungkinkan kita menghancurkan penalaran kita. Ini termasuk tetapi tidak terbatas pada:
- efek samping dengan sistem eksternal
- refleksi
Obat generik yang tidak terhapus dalam banyak hal terkait dengan refleksi. Tanpa penghapusan ada informasi runtime yang dibawa dengan implementasi yang dapat kita gunakan untuk mendesain algoritma kita. Artinya, secara statis, ketika kita berpikir tentang program, kita tidak memiliki gambaran yang lengkap. Refleksi sangat mengancam kebenaran dari bukti apa pun yang kami pertimbangkan secara statis. Bukan kebetulan refleksi juga menyebabkan berbagai cacat rumit.
Jadi apa cara obat generik tak terhapus bisa "berguna?" Mari pertimbangkan penggunaan yang disebutkan dalam tweet:
<T> T broken { return new T(); }
Apa yang terjadi jika T tidak memiliki konstruktor no-arg? Dalam beberapa bahasa, apa yang Anda dapatkan adalah null. Atau mungkin Anda melewatkan nilai null dan langsung memunculkan pengecualian (yang tampaknya mengarah ke nilai null). Karena bahasa kami Turing lengkap, tidak mungkin untuk menentukan panggilan manabroken
akan melibatkan tipe "aman" dengan konstruktor tanpa argumen dan mana yang tidak. Kami telah kehilangan kepastian bahwa program kami bekerja secara universal.
Menghapus berarti kita sudah beralasan (jadi mari kita hapus)
Jadi jika kami ingin bernalar tentang program kami, kami sangat disarankan untuk tidak menggunakan fitur bahasa yang sangat mengancam penalaran kami. Setelah kita melakukan itu, lalu mengapa tidak menjatuhkan tipe pada saat runtime? Mereka tidak dibutuhkan. Kita bisa mendapatkan efisiensi dan kesederhanaan dengan kepuasan bahwa tidak ada pemeran yang gagal atau metode mungkin hilang saat pemanggilan.
Menghapus mendorong penalaran.