Saya membaca tweet hari ini yang mengatakan:
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.
Jadi pertanyaan saya adalah:
Apakah ada manfaat dari penghapusan tipe Java? Apa keuntungan teknis atau gaya pemrograman yang (mungkin) tawarkan selain preferensi implementasi JVM untuk kompatibilitas mundur dan kinerja runtime?
java
type-erasure
vertti
sumber
sumber
Jawaban:
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:
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
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
kita bisa beralasan itu
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:
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:
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 mana
broken
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.
sumber
Tipe adalah konstruksi yang digunakan untuk menulis program dengan cara yang memungkinkan kompilator untuk memeriksa kebenaran program. Tipe adalah proposisi pada nilai - kompilator memverifikasi bahwa proposisi ini benar.
Selama menjalankan sebuah program, seharusnya tidak diperlukan informasi tipe - ini telah diverifikasi oleh kompilator. Kompilator harus bebas membuang informasi ini untuk melakukan pengoptimalan pada kode - membuatnya berjalan lebih cepat, menghasilkan biner yang lebih kecil, dll. Penghapusan parameter tipe memfasilitasi ini.
Java memecah pengetikan statis dengan mengizinkan informasi jenis ditanyakan saat runtime - refleksi, instance, dll. Hal ini memungkinkan Anda untuk membangun program yang tidak dapat diverifikasi secara statis - mereka melewati sistem jenis. Itu juga melewatkan peluang untuk pengoptimalan statis.
Fakta bahwa parameter tipe dihapus mencegah beberapa contoh program yang salah ini untuk dibangun, namun, program yang lebih salah akan dilarang jika informasi tipe lebih banyak dihapus dan refleksi serta fasilitas instans dihapus.
Penghapusan penting untuk mempertahankan properti "parametrik" tipe data. Katakanlah saya memiliki tipe "Daftar" yang diparameterisasi di atas komponen tipe T. yaitu Daftar <T>. Tipe itu adalah proposisi bahwa tipe Daftar ini bekerja secara identik untuk semua tipe T. Fakta bahwa T adalah parameter tipe abstrak dan tak terbatas berarti bahwa kita tidak tahu apa-apa tentang tipe ini, oleh karena itu dilarang melakukan sesuatu yang khusus untuk kasus khusus T.
misalnya mengatakan saya memiliki Daftar xs = asList ("3"). Saya menambahkan elemen: xs.add ("q"). Saya berakhir dengan ["3", "q"]. Karena ini parametrik, saya dapat mengasumsikan bahwa List xs = asList (7); xs.add (8) diakhiri dengan [7,8] Saya tahu dari tipe bahwa ia tidak melakukan satu hal untuk String dan satu hal untuk Int.
Lebih jauh, saya tahu bahwa fungsi List.add tidak dapat menemukan nilai T dari udara tipis. Saya tahu bahwa jika asList saya ("3") memiliki "7" yang ditambahkan ke dalamnya, satu-satunya jawaban yang mungkin akan dibuat dari nilai "3" dan "7". Tidak ada kemungkinan "2" atau "z" ditambahkan ke daftar karena fungsi tidak dapat membangunnya. Tak satu pun dari nilai-nilai lain ini akan masuk akal untuk ditambahkan, dan parametrikitas mencegah program yang salah ini dibangun.
Pada dasarnya, penghapusan mencegah beberapa cara melanggar parametrik, sehingga menghilangkan kemungkinan program yang salah, yang merupakan tujuan pengetikan statis.
sumber
(Meskipun saya sudah menulis jawaban di sini, meninjau kembali pertanyaan ini dua tahun kemudian saya menyadari ada cara lain yang sama sekali berbeda untuk menjawabnya, jadi saya membiarkan jawaban sebelumnya tetap utuh dan menambahkan yang ini.)
Sangat diperdebatkan apakah proses yang dilakukan pada Java Generics layak diberi nama "penghapusan tipe". Karena tipe generik tidak dihapus tetapi diganti dengan tipe mentahnya, pilihan yang lebih baik sepertinya adalah "tipe mutilasi".
Fitur klasik dari penghapusan tipe dalam pengertian yang umum dipahami memaksa runtime untuk tetap berada dalam batas-batas sistem tipe statis dengan membuatnya "buta" terhadap struktur data yang diaksesnya. Ini memberikan kekuatan penuh kepada kompilator dan memungkinkannya untuk membuktikan teorema berdasarkan tipe statis saja. Ini juga membantu programmer dengan membatasi derajat kebebasan kode, memberikan lebih banyak kekuatan untuk penalaran sederhana.
Penghapusan jenis Java tidak mencapai itu — ia melumpuhkan kompilator, seperti dalam contoh ini:
(Dua deklarasi di atas diciutkan ke dalam tanda tangan metode yang sama setelah penghapusan.)
Di sisi lain, runtime masih dapat memeriksa jenis objek dan alasannya, tetapi karena wawasannya tentang jenis sebenarnya terhambat oleh penghapusan, pelanggaran jenis statis mudah dicapai dan sulit dicegah.
Untuk membuat segalanya lebih berbelit-belit, tanda tangan tipe asli dan yang dihapus hidup berdampingan dan dianggap paralel selama kompilasi. Ini karena seluruh proses bukan tentang menghapus informasi jenis dari runtime, tetapi tentang menyatukan sistem jenis generik ke dalam sistem jenis mentah lama untuk mempertahankan kompatibilitas ke belakang. Permata ini adalah contoh klasik:
(Redundan
extends Object
harus ditambahkan untuk menjaga kompatibilitas mundur dari tanda tangan yang dihapus.)Sekarang, dengan mengingat hal itu, mari kita lihat kembali kutipannya:
Apa sebenarnya yang dilakukan Java dengan benar? Apakah itu kata itu sendiri, apa pun artinya? Untuk kontras, lihat
int
jenis yang sederhana : tidak ada pemeriksaan jenis runtime yang pernah dilakukan, atau bahkan mungkin, dan eksekusi selalu aman untuk jenis yang sempurna. Yang ini apa penghapusan jenis terlihat seperti bila dilakukan dengan benar: Anda bahkan tidak tahu itu ada.sumber
Satu hal yang saya tidak lihat dipertimbangkan di sini sama sekali adalah bahwa polimorfisme runtime OOP pada dasarnya bergantung pada reifikasi tipe pada saat runtime. Ketika sebuah bahasa yang tulang punggungnya dipegang oleh tipe refied memperkenalkan perluasan besar pada sistem tipenya dan mendasarkannya pada penghapusan tipe, disonansi kognitif adalah hasil yang tak terelakkan. Inilah yang terjadi pada komunitas Jawa; itulah mengapa penghapusan tipe telah menarik begitu banyak kontroversi, dan pada akhirnya mengapa ada rencana untuk membatalkannya di rilis Java mendatang . Menemukan sesuatu yang lucu dalam keluhan pengguna Java itu menunjukkan kesalahpahaman yang jujur tentang semangat Jawa, atau lelucon yang secara sadar mencela.
Klaim "penghapusan adalah satu-satunya hal yang Java benar" menyiratkan klaim bahwa "semua bahasa yang didasarkan pada pengiriman dinamis terhadap jenis runtime argumen fungsi pada dasarnya cacat". Meskipun tentu saja merupakan klaim yang sah dengan sendirinya, dan yang bahkan dapat dianggap sebagai kritik yang valid untuk semua bahasa OOP termasuk Java, ia tidak dapat menempatkan dirinya sebagai titik penting untuk mengevaluasi dan mengkritik fitur dalam konteks Java , di mana runtime polimorfisme bersifat aksiomatik.
Singkatnya, sementara seseorang dapat secara valid menyatakan "penghapusan jenis adalah cara untuk masuk dalam desain bahasa", posisi yang mendukung penghapusan jenis dalam Java salah tempat hanya karena sudah sangat, sangat terlambat untuk itu dan telah terjadi bahkan pada saat bersejarah ketika Oak dipeluk oleh Sun dan diganti namanya menjadi Java.
Mengenai apakah pengetikan statis itu sendiri adalah arah yang tepat dalam desain bahasa pemrograman, ini cocok dengan konteks filosofis yang lebih luas dari apa yang menurut kami merupakan aktivitas pemrograman . Satu aliran pemikiran, yang secara jelas berasal dari tradisi klasik matematika, melihat program sebagai contoh dari satu konsep matematika atau lainnya (proposisi, fungsi, dll.), Tetapi terdapat kelas pendekatan yang sama sekali berbeda, yang melihat pemrograman sebagai cara untuk berbicara dengan mesin dan menjelaskan apa yang kita inginkan darinya. Dalam pandangan ini, program adalah entitas yang dinamis dan tumbuh secara organik, kebalikan dramatis dari aedifice yang didirikan dengan hati-hati dari program yang diketik secara statis.
Tampaknya wajar untuk menganggap bahasa dinamis sebagai langkah ke arah itu: konsistensi program muncul dari bawah ke atas, tanpa batasan apriori yang akan memaksakannya secara top-down. Paradigma ini dapat dilihat sebagai langkah menuju pemodelan proses dimana kita, manusia, menjadi apa adanya melalui pengembangan dan pembelajaran.
sumber
Postingan berikutnya dari pengguna yang sama dalam percakapan yang sama:
(Ini adalah tanggapan atas pernyataan oleh pengguna lain, yaitu bahwa "tampaknya dalam beberapa situasi 'T baru' akan lebih baik", idenya
new T()
adalah tidak mungkin karena penghapusan jenis. (Ini masih bisa diperdebatkan - bahkan jikaT
tersedia di runtime, bisa jadi kelas atau antarmuka abstrak, atau bisa jugaVoid
, atau bisa jadi tidak ada konstruktor no-arg, atau konstruktor no-arg-nya bisa jadi privat (misalnya, karena itu seharusnya kelas tunggal), atau konstruktor no-arg dapat menentukan pengecualian yang dicentang yang tidak ditangkap atau ditentukan oleh metode generik - tetapi itulah premisnya. Terlepas dari itu, memang benar bahwa tanpa penghapusan Anda setidaknya dapat menulisT.class.newInstance()
, yang menangani masalah tersebut.))Pandangan ini, bahwa tipe isomorfik terhadap proposisi, menunjukkan bahwa pengguna memiliki latar belakang dalam teori tipe formal. (S) dia sangat mungkin tidak menyukai "tipe dinamis" atau "tipe runtime" dan lebih memilih Java tanpa downcast
instanceof
dan refleksi dan seterusnya. (Bayangkan bahasa seperti ML Standar, yang memiliki sistem jenis yang sangat kaya (statis) dan yang semantik dinamisnya tidak bergantung pada jenis informasi apa pun.)Omong-omong, perlu diingat bahwa pengguna sedang melakukan trolling: meskipun dia cenderung dengan tulus lebih memilih bahasa yang diketik (secara statis), dia tidak dengan tulus mencoba meyakinkan orang lain tentang pandangan tersebut. Sebaliknya, tujuan utama dari tweet asli adalah untuk mengejek mereka yang tidak setuju, dan setelah beberapa dari mereka yang tidak setuju menimpali, pengguna memposting tweet lanjutan seperti "alasan java memiliki penghapusan tipe adalah karena Wadler dkk tahu apa yang mereka lakukan, tidak seperti pengguna java ". Sayangnya, hal ini membuat sulit untuk mengetahui apa yang sebenarnya dia pikirkan; tetapi untungnya, itu juga mungkin berarti bahwa itu tidak terlalu penting untuk dilakukan. Orang-orang dengan kedalaman sebenarnya pada pandangan mereka biasanya tidak menggunakan troll yang cukup bebas konten ini.
sumber
Satu hal yang baik adalah tidak perlu mengubah JVM saat obat generik diperkenalkan. Java mengimplementasikan generik hanya pada level compiler.
sumber
Alasan penghapusan jenis adalah hal yang baik adalah karena hal-hal yang tidak memungkinkan itu berbahaya. Mencegah pemeriksaan argumen tipe pada waktu proses membuat pemahaman dan penalaran tentang program lebih mudah.
Pengamatan yang saya temukan agak kontra-intuitif adalah bahwa ketika tanda tangan fungsi lebih umum, tanda tangan fungsi menjadi lebih mudah dipahami. Ini karena jumlah implementasi yang mungkin berkurang. Pertimbangkan metode dengan tanda tangan ini, yang entah bagaimana kita tahu tidak memiliki efek samping:
Apa kemungkinan implementasi dari fungsi ini? Sangat banyak. Anda hanya dapat mengetahui sedikit tentang fungsi ini. Ini bisa membalik daftar masukan. Itu bisa memasangkan int bersama-sama, menjumlahkannya dan mengembalikan daftar setengah ukuran. Ada banyak kemungkinan lain yang bisa dibayangkan. Sekarang pertimbangkan:
Ada berapa implementasi fungsi ini? Karena implementasi tidak dapat mengetahui jenis elemen, sejumlah besar implementasi sekarang dapat dikecualikan: elemen tidak dapat digabungkan, atau ditambahkan ke daftar atau disaring, dkk. Kami dibatasi pada hal-hal seperti: identitas (tidak ada perubahan pada daftar), menghapus elemen, atau membalik daftar. Fungsi ini lebih mudah dipikirkan berdasarkan tanda tangannya saja.
Kecuali… di Jawa Anda selalu bisa menipu sistem tipe. Karena penerapan metode umum tersebut dapat menggunakan hal-hal seperti
instanceof
cek dan / atau gips ke jenis arbitrer, penalaran kita berdasarkan tanda tangan jenis dapat dengan mudah dianggap tidak berguna. Fungsi tersebut dapat memeriksa jenis elemen dan melakukan sejumlah hal berdasarkan hasilnya. Jika peretasan waktu proses ini diizinkan, tanda tangan metode berparameterisasi menjadi kurang berguna bagi kami.Jika Java tidak memiliki penghapusan tipe (yaitu, argumen tipe direifikasi saat runtime) maka ini hanya akan memungkinkan lebih banyak kejahatan yang merusak penalaran semacam ini. Dalam contoh di atas, implementasi hanya dapat melanggar ekspektasi yang ditetapkan oleh tanda tangan tipe jika daftar tersebut memiliki setidaknya satu elemen; tetapi jika
T
direifikasi, ia dapat melakukannya meskipun daftarnya kosong. Tipe yang direifikasi hanya akan meningkatkan kemungkinan (sudah sangat banyak) untuk menghalangi pemahaman kita tentang kode.Penghapusan jenis membuat bahasa menjadi kurang "kuat". Tetapi beberapa bentuk "kekuatan" sebenarnya berbahaya.
sumber
instanceof
menghalangi kemampuan kita untuk bernalar tentang apa yang dilakukan kode berdasarkan jenis. Jika Java harus mereifikasi argumen tipe, itu hanya akan membuat masalah ini menjadi lebih buruk. Menghapus tipe pada waktu proses memiliki efek membuat sistem tipe lebih berguna.Ini bukan jawaban langsung (OP ditanya "apa manfaatnya", saya jawab "apa kontra")
Dibandingkan dengan sistem tipe C #, penghapusan tipe Java sangat merepotkan untuk dua serangan
Anda tidak dapat mengimplementasikan sebuah antarmuka dua kali
Dalam C # Anda dapat mengimplementasikan keduanya
IEnumerable<T1>
danIEnumerable<T2>
dengan aman, terutama jika kedua tipe tidak berbagi satu leluhur yang sama (yaitu leluhur mereka adalahObject
).Contoh praktis: di Spring Framework, Anda tidak dapat mengimplementasikan
ApplicationListener<? extends ApplicationEvent>
beberapa kali. Jika Anda membutuhkan perilaku yang berbeda berdasarkanT
Anda perlu mengujiinstanceof
Anda tidak dapat melakukan T baru ()
(dan Anda memerlukan referensi ke Kelas untuk melakukan itu)
Seperti yang dikomentari orang lain, melakukan padanan dengan
new T()
hanya dapat dilakukan melalui refleksi, hanya dengan memanggil sebuah instanceClass<T>
, memastikan tentang parameter yang dibutuhkan oleh konstruktor. C # memungkinkan Anda melakukannew T()
hanya jika Anda membatasiT
ke konstruktor tanpa parameter. JikaT
tidak menghormati batasan itu, kesalahan kompilasi akan muncul.Di Java, Anda akan sering dipaksa untuk menulis metode yang terlihat seperti berikut ini
Kekurangan pada kode di atas adalah:
ReflectiveOperationException
akan dilempar saat runtimeJika saya adalah penulis C #, saya akan memperkenalkan kemampuan untuk menentukan satu atau lebih batasan konstruktor yang mudah diverifikasi pada waktu kompilasi (jadi saya dapat meminta misalnya konstruktor dengan
string,string
params). Tapi yang terakhir adalah spekulasisumber
Poin tambahan yang tampaknya tidak dipertimbangkan oleh jawaban lain: jika Anda benar-benar membutuhkan obat generik dengan pengetikan run-time, Anda dapat menerapkannya sendiri seperti ini:
Kelas ini kemudian dapat melakukan semua hal yang dapat dicapai secara default jika Java tidak menggunakan penghapusan: ia dapat mengalokasikan
T
s baru (dengan asumsiT
memiliki konstruktor yang cocok dengan pola yang diharapkan untuk digunakan), atau arrayT
s, ia dapat menguji secara dinamis pada waktu proses jika objek tertentu adalah aT
dan mengubah perilaku bergantung padanya, dan seterusnya.Sebagai contoh:
sumber
menghindari c ++ - seperti kode mengasapi karena kode yang sama digunakan untuk beberapa tipe; Namun, penghapusan tipe memerlukan pengiriman virtual sedangkan pendekatan c ++ - code-bloat dapat melakukan pengiriman generik yang tidak dikirim secara virtual
sumber
Sebagian besar jawaban lebih memperhatikan filosofi pemrograman daripada detail teknis yang sebenarnya.
Dan meskipun pertanyaan ini berusia lebih dari 5 tahun, pertanyaannya masih tetap ada: Mengapa penghapusan jenis diinginkan dari sudut pandang teknis? Pada akhirnya, jawabannya cukup sederhana (pada level yang lebih tinggi): https://en.wikipedia.org/wiki/Type_erasure
Template C ++ tidak ada saat runtime. Kompilator mengeluarkan versi yang dioptimalkan sepenuhnya untuk setiap pemanggilan, yang berarti eksekusi tidak bergantung pada informasi jenis. Tapi bagaimana JIT menangani versi berbeda dari fungsi yang sama? Bukankah lebih baik hanya memiliki satu fungsi? Tidak ingin JIT harus mengoptimalkan semua versi yang berbeda darinya. Nah, lalu bagaimana dengan keamanan tipe? Tebak itu harus keluar dari jendela.
Tapi tunggu sebentar: Bagaimana .NET melakukannya? Refleksi! Dengan cara ini mereka hanya perlu mengoptimalkan satu fungsi dan juga mendapatkan informasi jenis runtime. Dan itulah mengapa .NET generik dulunya lebih lambat (meskipun menjadi jauh lebih baik). Saya tidak berpendapat bahwa itu tidak nyaman! Tetapi itu mahal dan tidak boleh digunakan ketika itu tidak mutlak diperlukan (itu tidak dianggap mahal dalam bahasa yang diketik secara dinamis karena kompiler / interpreter tetap bergantung pada refleksi).
Dengan cara ini pemrograman generik dengan penghapusan tipe mendekati nol overhead (beberapa pemeriksaan / gips runtime masih diperlukan): https://docs.oracle.com/javase/tutorial/java/generics/erasure.html
sumber