Tampaknya semua bahasa pemrograman baru atau setidaknya yang menjadi populer menggunakan inferensi tipe. Bahkan Javascript mendapat jenis dan tipe inferensi melalui berbagai implementasi (Acscript, typescript dll). Itu tampak hebat bagi saya tapi saya bertanya-tanya apakah ada trade-off atau mengapa katakanlah Java atau bahasa-bahasa lama yang baik tidak memiliki inferensi jenis
- Ketika mendeklarasikan variabel di Go tanpa menentukan jenisnya (menggunakan var tanpa tipe atau: = sintaks), tipe variabel disimpulkan dari nilai di sisi kanan.
- D memungkinkan penulisan fragmen kode besar tanpa menentukan jenis yang berlebihan, seperti yang dilakukan oleh bahasa dinamis. Di sisi lain, inferensi statis menyimpulkan jenis dan properti kode lainnya, memberikan yang terbaik dari dunia statis dan dinamis.
- Jenis mesin inferensi di Rust cukup cerdas. Itu lebih dari melihat jenis nilai-r selama inisialisasi. Ini juga terlihat bagaimana variabel digunakan setelahnya untuk menyimpulkan tipenya.
- Swift menggunakan inferensi tipe untuk mengetahui tipe yang sesuai. Ketik inferensi memungkinkan kompiler untuk menyimpulkan jenis ekspresi tertentu secara otomatis ketika mengkompilasi kode Anda, hanya dengan memeriksa nilai-nilai yang Anda berikan.
programming-languages
type-systems
Pengguna tanpa topi
sumber
sumber
var
karena kadang-kadang dapat merusak keterbacaan.var
dan C ++auto
) dan tipe inferensi (dua arah, seperti Haskelllet
). Dalam kasus sebelumnya, jenis nama dapat disimpulkan dari penginisialisasi saja — penggunaannya harus mengikuti jenis nama. Dalam kasus yang terakhir, jenis nama dapat disimpulkan dari penggunaannya juga — yang berguna karena Anda dapat menulis hanya[]
untuk urutan kosong, terlepas dari jenis elemen, ataunewEmptyMVar
untuk referensi nol yang dapat diubah baru, terlepas dari referensi mengetik.Jawaban:
Sistem tipe Haskell sepenuhnya dapat disimpulkan (mengesampingkan rekursi polimorfik, ekstensi bahasa tertentu , dan pembatasan monomorfisme yang ditakuti ), namun programmer masih sering memberikan anotasi jenis dalam kode sumber bahkan ketika mereka tidak perlu. Mengapa?
map :: (a -> b) -> [a] -> [b]
. Bentuk yang lebih umum (fmap :: Functor f => (a -> b) -> f a -> f b
) berlaku untuk semuaFunctor
, bukan hanya daftar. Tetapi dirasakan bahwamap
akan lebih mudah dipahami bagi pemula, sehingga ia hidup bersama kakaknya yang lebih besar.Secara keseluruhan, kelemahan dari sistem yang diketik secara statis tetapi dapat disimpulkan sama dengan kelemahan dari pengetikan statis secara umum, diskusi usang di situs ini dan yang lainnya (Googling "kekurangan pengetikan statis" akan membuat Anda ratusan halaman nyala api). Tentu saja, beberapa kerugian tersebut diperbaiki dengan jumlah anotasi jenis yang lebih kecil dalam sistem yang dapat disimpulkan. Plus, inferensi tipe memiliki kelebihannya sendiri: pengembangan hole-driven tidak akan mungkin tanpa inferensi tipe.
Java * membuktikan bahwa bahasa yang membutuhkan terlalu banyak anotasi jenis menjadi menjengkelkan, tetapi dengan terlalu sedikit Anda kehilangan kelebihan yang saya jelaskan di atas. Bahasa-bahasa dengan inferensi penyisihan keluar-jenis memberikan keseimbangan yang disetujui antara kedua ekstrem.
* Bahkan Java, kambing hitam yang hebat, melakukan sejumlah inferensi tipe lokal . Dalam pernyataan seperti
Map<String, Integer> = new HashMap<>();
, Anda tidak harus menentukan tipe generik konstruktor. Di sisi lain, bahasa gaya-ML biasanya tidak dapat ditebak secara global .sumber
Functor
. Daftar danmap
lebih mungkin akrab dengan Haskellers yang tidak berpengalaman.var
sebagai contoh inferensi tipe?var
adalah contoh yang tepat.x
; dalam yang terakhir tidak ada tipe untuk menentukan, semua tipe diketahui dan Anda hanya perlu memeriksa bahwa ungkapan itu masuk akal. Perbedaannya menjadi lebih penting ketika Anda melewati contoh-contoh sepele danx
digunakan di banyak tempat; kompiler kemudian harus memeriksa ulang lokasi di manax
digunakan untuk menentukan 1) apakah mungkin untuk menetapkanx
jenis sehingga kode akan mengetik cek? 2) Jika ya, jenis apa yang paling umum yang dapat kita tetapkan?new HashMap<>();
sintaks hanya ditambahkan di Java 7, dan lambdas di Java 8 memungkinkan untuk banyak inferensi tipe "nyata".Dalam C #, ketik inferensi terjadi pada waktu kompilasi, sehingga biaya runtime adalah nol.
Sebagai gaya,
var
digunakan untuk situasi di mana tidak nyaman atau tidak perlu untuk menentukan jenisnya secara manual. Linq adalah salah satu situasi seperti itu. Lainnya adalah:tanpanya Anda akan mengulang nama tipe yang sangat panjang (dan parameter tipe) daripada hanya mengatakan
var
.Gunakan nama sebenarnya dari tipe ini ketika secara eksplisit meningkatkan kejelasan kode.
Ada beberapa situasi di mana tipe inferensi tidak dapat digunakan, seperti deklarasi variabel anggota yang nilainya ditetapkan pada waktu konstruksi, atau di mana Anda benar-benar ingin intellisense berfungsi dengan baik (Hackerrank's IDE tidak akan menginternisikan anggota variabel kecuali jika Anda menyatakan jenisnya secara eksplisit) .
sumber
Pertanyaan bagus!
Dan ada lebih banyak bahasa esoterik yang tidak dapat melakukan keanehan mereka tanpa anotasi jenis eksplisit. Sejauh ini, tidak ada yang saya tahu yang umum / populer / cukup menjanjikan untuk disebutkan kecuali secara sepintas.
sumber
var foo = x => x;
gagal karena bahasa perlu disimpulkan dix
sini dan tidak ada yang perlu dilanjutkan. Ketika lambda dibangun, mereka dibangun sebagai delegasi yang diketik secara eksplisitFunc<int, int> foo = x => x
dibangun ke dalam CIL sebagaiFunc<int, int> foo = new Func<int, int>(x=>x);
tempat lambda dibangun sebagai fungsi yang dihasilkan, yang diketik secara eksplisit. Bagi saya, menyimpulkan tipex
bagian dan paket inferensi tipe ...x => x
terkandung di dalam lambda itu sendiri - itu tidak merujuk ke variabel apa pun dari lingkup sekitarnya. Bahasa fungsional yang waras akan menyimpulkan dengan benar bahwa tipenya adalah "untuk semua jenisa
,a -> a
". Saya pikir apa yang ingin dikatakan oleh DeadMG adalah bahwa sistem tipe C # tidak memiliki properti tipe utama yang berarti bahwa selalu mungkin untuk mengetahui tipe yang paling umum untuk ekspresi apa pun. Ini properti yang sangat mudah dihancurkan.Kebetulan Java menjadi pengecualian daripada aturan di sini. Bahkan C ++ (yang saya percaya memenuhi syarat sebagai "bahasa tua yang baik" :)) mendukung inferensi jenis dengan
auto
kata kunci sejak standar C ++ 11. Ini tidak hanya bekerja dengan deklarasi variabel, tetapi juga sebagai tipe fungsi pengembalian, yang sangat berguna dengan beberapa fungsi template yang kompleks.Mengetik dan mengetik inferensi implisit memiliki banyak kasus penggunaan yang baik, dan ada juga beberapa kasus penggunaan di mana Anda benar-benar tidak boleh melakukannya. Ini terkadang masalah selera, dan juga menjadi bahan perdebatan.
Tetapi tidak diragukan lagi bahwa ada kasus penggunaan yang baik, dengan sendirinya merupakan alasan yang sah untuk bahasa apa pun untuk mengimplementasikannya. Ini juga bukan fitur yang sulit untuk diimplementasikan, tidak ada penalti runtime, dan tidak mempengaruhi waktu kompilasi secara signifikan.
Saya tidak melihat kelemahan nyata dalam memberikan kesempatan kepada pengembang untuk menggunakan inferensi tipe.
Beberapa penjawab menimbang-nebak seberapa baik mengetik eksplisit itu baik, dan tentu saja itu benar. Tetapi tidak mendukung pengetikan tersirat akan berarti bahwa suatu bahasa memaksakan pengetikan eksplisit sepanjang waktu.
Jadi penarikan sebenarnya adalah ketika sebuah bahasa tidak mendukung pengetikan tersirat, karena dengan ini menyatakan, bahwa tidak ada alasan yang sah bagi pengembang untuk menggunakannya, yang tidak benar.
sumber
Perbedaan utama antara sistem inferensi tipe Hindley-Milner dan inferensi tipe Go-style adalah arah aliran informasi. Di HM, ketik informasi mengalir maju dan mundur melalui penyatuan; di Go, ketik hanya arus informasi yang mengalir: ia menghitung maju hanya penggantian.
Inferensi tipe HM adalah inovasi hebat yang bekerja dengan baik dengan bahasa fungsional yang diketik secara polimorfik, tetapi penulis Go mungkin berpendapat bahwa ini mencoba melakukan terlalu banyak:
Fakta bahwa informasi mengalir baik ke depan maupun ke belakang berarti bahwa inferensi tipe HM adalah urusan yang sangat non-lokal; jika tidak ada anotasi jenis, setiap baris kode dalam program Anda dapat berkontribusi pada pengetikan satu baris kode. Jika Anda hanya memiliki substitusi maju, Anda tahu bahwa sumber kesalahan tipe harus dalam kode yang mendahului kesalahan Anda; bukan kode yang muncul setelahnya.
Dengan inferensi tipe HM, Anda cenderung berpikir dalam kendala: ketika Anda menggunakan suatu jenis, Anda membatasi jenis apa yang mungkin dimiliki. Pada akhirnya, mungkin ada beberapa variabel tipe yang dibiarkan sama sekali tidak dibatasi. Wawasan dari inferensi tipe HM adalah bahwa, tipe-tipe itu benar-benar tidak penting, sehingga mereka dibuat menjadi variabel polimorfik. Namun, polimorfisme ekstra ini dapat tidak diinginkan karena sejumlah alasan. Pertama, seperti yang ditunjukkan oleh beberapa orang, polimorfisme ekstra ini mungkin tidak diinginkan: HM menyimpulkan tipe palsu, polimorfik untuk beberapa kode palsu, dan menyebabkan kesalahan aneh nantinya. Kedua, ketika suatu tipe dibiarkan polimorfik, ini dapat memiliki konsekuensi untuk perilaku runtime. Misalnya, hasil antara yang terlalu polimorfik adalah alasan mengapa 'ditampilkan. baca 'dianggap ambigu dalam Haskell; sebagai contoh lain,
sumber
Itu menyakitkan keterbacaan.
Membandingkan
vs.
Terutama masalah ketika membaca di luar IDE seperti di github.
sumber
var
dapat digunakan tanpa merusak keterbacaan.var objects = GetBusinessObjects();