Mengapa Java tidak melakukan inferensi tipe?

44

Saya selalu bertanya-tanya mengapa Java tidak melakukan inferensi ketik mengingat bahasanya memang seperti itu, dan VM-nya sangat matang. Google's Go adalah contoh bahasa dengan inferensi jenis yang sangat baik dan mengurangi jumlah pengetikan yang harus dilakukan. Apakah ada alasan khusus di balik fitur ini yang tidak menjadi bagian dari Java?

cobie
sumber
3
aturan kompatibilitas mundur dalam bahasa yang sama tuanya dan sepopuler java
ratchet freak
9
@ scratchetfreak Bisakah mengetik inferensi tidak ditambahkan dengan cara yang kompatibel dengan mundur? Program yang lebih lama hanya akan memberikan lebih banyak jenis informasi daripada yang diperlukan.
1
Ini mungkin memiliki beberapa efek yang tidak diinginkan ketika digunakan dengan Type Erasure. docs.oracle.com/javase/tutorial/java/generics/…
Zachary Yates
4
Perhatikan bahwa Java 8 akan membawa banyak inferensi tipe dengan fitur Lambda-nya: Anda dapat menulis lambda kompleks tanpa menyebutkan jenis dan segala yang disimpulkan.
Joachim Sauer
4
Inferensi tipe variabel lokal akan datang ke Jawa: JEP 286: Inferensi Tipe Variabel Lokal
Jimmy Page

Jawaban:

60

Secara teknis, Java memang memiliki tipe inferencing saat menggunakan obat generik. Dengan metode generik suka

public <T> T foo(T t) {
  return t;
}

Kompiler akan menganalisis dan memahami hal itu ketika Anda menulis

// String
foo("bar");
// Integer
foo(new Integer(42));

Sebuah String akan dikembalikan untuk panggilan pertama dan Integer untuk panggilan kedua berdasarkan apa yang dimasukkan sebagai argumen. Anda akan mendapatkan waktu kompilasi yang tepat sebagai hasilnya. Selain itu, di Java 7, seseorang bisa mendapatkan beberapa tipe tambahan yang menyimpulkan ketika instantiating generik seperti itu

Map<String, String> foo = new HashMap<>();

Java cukup baik untuk mengisi kurung sudut kosong untuk kita. Sekarang mengapa Java tidak mendukung penaksiran tipe sebagai bagian dari penugasan variabel? Pada satu titik, ada RFE untuk tipe yang menyimpulkan dalam deklarasi variabel, tetapi ini ditutup sebagai "Tidak akan diperbaiki" karena

Manusia mendapat manfaat dari redundansi deklarasi tipe dalam dua cara. Pertama, tipe redundan berfungsi sebagai dokumentasi yang berharga - pembaca tidak harus mencari deklarasi getMap () untuk mengetahui tipe apa yang dikembalikan. Kedua, redundansi memungkinkan programmer untuk mendeklarasikan tipe yang dimaksud, dan karenanya mendapat manfaat dari pemeriksaan silang yang dilakukan oleh kompiler.

Kontributor yang menutup ini juga mencatat bahwa rasanya "tidak seperti java", yang saya setujui. Kata kerja Jawa bisa menjadi berkah sekaligus kutukan, tetapi itu membuat bahasa itu seperti apa adanya.

Tentu saja RFE tertentu itu bukan akhir dari percakapan itu. Selama Java 7, fitur ini sekali lagi dipertimbangkan , dengan beberapa implementasi pengujian dibuat, termasuk satu oleh James Gosling sendiri. Sekali lagi, fitur ini akhirnya ditembak jatuh.

Dengan dirilisnya Java 8, kami sekarang mendapatkan inferensi jenis sebagai bagian dari lambdas sebagai berikut:

List<String> names = Arrays.asList("Tom", "Dick", "Harry");
Collections.sort(names, (first, second) -> first.compareTo(second));

Kompiler Java dapat melihat metode Collections#sort(List<T>, Comparator<? super T>)dan kemudian antarmuka Comparator#compare(T o1, T o2)dan menentukan itu firstdan secondharus dengan Stringdemikian memungkinkan programmer untuk melupakan harus menyatakan kembali jenis dalam ekspresi lambda.

Pang
sumber
5
First, the redundant type serves as valuable documentation - readers do not have to search for the declaration of getMap() to find out what type it returns- ya, jika HashMap<String, Integer> map = foo.getMap()kemudian saya setuju - dalam C # Saya biasanya tidak menggunakan vardalam kasus seperti itu, meskipun saya bisa. Tetapi argumen ini tidak menahan air jika itu HashMap<String, Integer> map = new HashMap<String, Integer>(). Ini benar-benar redundansi dan saya melihat tidak ada manfaatnya karena harus menulis nama tipe dua kali. Dan bagaimana saya akan mendapat manfaat di sini dari pemeriksaan silang kompiler, saya tidak mengerti sama sekali.
Konrad Morawski
9
Ya dan itu bagus untuk obat generik, tapi saya masih ketinggalan setara dengan C # vardi Jawa.
Konrad Morawski
15
Mengenai "tidak-seperti-Jawa", kisah (murahan) ini muncul di benak;) 9gag.com/gag/2308699/-ini-adalah-bagaimana-satu-yang-melakukan-ditempat-di sini
Konrad Morawski
6
Lebih jauh lagi, tipe kembalinya suatu fungsi sering kali jelas atau tidak perlu, dan bahkan dalam kasus di mana itu bukan IDE Anda dapat menandai tipe itu dalam setengah detik.
Phoshi
8
Saya percaya kutipan resmi Humans benefit from the redundancyadalah jawaban nyata untuk pertanyaan saat ini, karena setiap justifikasi yang saya baca tampaknya merupakan alasan yang tidak masuk akal, tidak berdasar, dan konyol dari para desainer Java: Baik C # dan C ++ memiliki fitur, desainer C # dan C ++ tidak kalah kompeten daripada Java, dan semua orang senang menggunakannya. Apa yang menyebabkan pengembang Java berbeda dari pengembang C # atau C ++? Ini adalah mengapa saya setuju dengan @KonradMorawski, "Ini adalah bagaimana hal-hal yang dilakukan di sini" tampaknya lagi menjadi alasan di balik layar nyata untuk itu.
paercebal
16

Yah, pertama-tama, tipe inferensi tidak ada hubungannya dengan kematangan runtime, apakah itu runtime adalah CPU berusia 30 tahun atau VM yang sangat baru bit-bitnya masih mengkilap. ini semua tentang kompiler.

Yang mengatakan, itu diperbolehkan untuk obat generik, alasan mengapa itu tidak diperbolehkan untuk jenis non-generik tampaknya karena filosofi - tidak ada yang mencegah desainer untuk menambahkannya.

Pembaruan: sepertinya java 10 mendukungnya —- http://openjdk.java.net/jeps/286

jmoreno
sumber
5

Sejauh yang saya tahu, ketika Java dirancang pada awal tahun sembilan puluhan jenis inferensi tidak begitu populer di antara bahasa-bahasa utama (tapi itu sudah konsep yang sangat terkenal, misalnya dalam ML). Jadi, saya bisa membayangkan bahwa inferensi jenis mungkin tidak didukung karena Java ditujukan untuk programmer yang berasal dari C ++, Pascal, atau bahasa utama lainnya yang tidak memilikinya (prinsip kejutan paling tidak).

Juga, salah satu prinsip desain Java adalah menulis hal-hal secara eksplisit untuk memastikan bahwa programmer dan kompiler memiliki pemahaman yang sama tentang kode: menggandakan informasi mengurangi kemungkinan kesalahan. Tentu saja, mungkin merupakan masalah selera apakah mengetik beberapa karakter sepadan dengan keamanan ekstra yang diberikannya, tetapi ini adalah filosofi desain yang diikuti untuk Jawa: menulis sesuatu secara eksplisit.

Saya tidak tahu apakah Java akan mendapatkan inferensi tipe di masa depan tetapi IMO yang akan menjadi revolusi besar untuk bahasa (seperti yang disebutkan Glenn Nelson, itu digambarkan sebagai "seperti-java-seperti") dan kemudian orang mungkin juga mempertimbangkan untuk menjatuhkan beri nama Java untuk nama baru.

Jika Anda ingin menggunakan bahasa JVM dengan tipe inferensi Anda dapat menggunakan Scala.

Giorgio
sumber
2

Saya dapat memikirkan beberapa kemungkinan alasan. Salah satunya adalah bahwa pengetikan secara eksplisit mendokumentasikan diri. Java umumnya menjadikan ini prioritas daripada keputusan. Alasan lain mungkin dalam kasus di mana jenisnya agak ambigu. Seperti ketika suatu jenis atau subtipe apa pun dapat memenuhi suatu rutinitas. Katakanlah Anda ingin menggunakan Daftar, tetapi seseorang datang dan menggunakan metode eksklusif untuk ArrayList. JIT akan menyimpulkan ArrayList dan melanjutkan bahkan jika Anda menginginkan kesalahan kompilasi.

jiggy
sumber
8
Bagaimana GridBagLayout gridbag = new GridBagLayout (); tambahkan ke dokumentasi diri? Pengulangan murni.
Anders Lindén
3
Ini terlepas dari kasus di mana kedua jenis tidak sama. Anda bisa dengan mudah menetapkan turunan dari subkelas.
jiggy
Let's say you want to use a List, but someone comes along and uses a method exclusive to ArrayList. The JIT would infer an ArrayList and carry on even if you wanted a compilation error- Saya tidak mengerti bagian ini. Ketik inferensi terjadi pada saat instatiating variabel, tidak memanggil metode di dalamnya. Bisakah Anda menunjukkan contoh dari apa yang Anda maksudkan?
Konrad Morawski
2
@KonradMorawski: Saya berasumsi dia berarti bahwa jika suatu metode mengembalikan ArrayList, jenisnya akan disimpulkan. Jika Anda ingin memperlakukan jenis sebagai sesuatu selain jenis kembali, Anda tidak dapat menggunakan inferensi. Saya tidak mengerti bagaimana ini bisa menjadi masalah dalam basis kode di dekat waras, meskipun.
Phoshi
JIT tidak akan memainkan peran apa pun dalam jenis inferensi. inferensi tipe adalah fenomena waktu kompilasi. dan jika variabel dinyatakan sebagai referensi ke Daftar, mencoba mengakses anggota ArrayList di atasnya tidak akan ketik cek dan Anda mendapatkan kesalahan kompilasi
sara
0

Ini bertentangan dengan rekomendasi mapan untuk mendeklarasikan variabel menggunakan antarmuka paling umum yang sesuai dengan kebutuhan Anda, dan menginisialisasi mereka dengan kelas implementasi yang tepat, seperti di

Collection<String> names = new ArrayList<>();

Secara efektif,

var names = new ArrayList<String>();

tidak lain adalah gula sintaksis untuk

ArrayList<String> names = new ArrayList<String>();

Jika Anda menginginkannya, IDE Anda dapat memproduksinya dari new ArrayList<String>()ekspresi dengan "satu klik" (refactor / create variabel lokal), tetapi ingat bahwa itu bertentangan dengan rekomendasi "gunakan antarmuka".

Ralf Kleberhoff
sumber