Alasan untuk penghapusan jenis fungsi di Java 8

12

Saya telah mencoba memahami mengapa JDK 8 Lambda Expert Group (EG) memutuskan untuk tidak memasukkan jenis fungsi baru ke dalam bahasa pemrograman Java.

Menuju milis saya menemukan utas dengan diskusi tentang penghapusan jenis fungsi .

Banyak pernyataan yang ambigu bagi saya, mungkin karena kurangnya konteks dan dalam beberapa kasus karena pengetahuan saya yang terbatas tentang implementasi sistem tipe.

Namun, ada beberapa pertanyaan yang saya yakin dapat dirumuskan dengan aman di situs ini untuk membantu saya memahami dengan lebih baik apa artinya.

Saya tahu saya bisa mengajukan pertanyaan di milis, tetapi utasnya sudah tua dan semua keputusan sudah dibuat, jadi kemungkinan besar saya akan diabaikan, terutama melihat bahwa orang-orang ini sudah tertunda dengan rencana mereka.

Dalam jawabannya untuk mendukung penghapusan tipe fungsi dan mendukung penggunaan tipe SAM, Brian Goetz mengatakan:

Tidak ada reifikasi. Ada utas panjang tentang seberapa berguna bagi jenis fungsi untuk diverifikasi. Tanpa reifikasi, tipe-tipe fungsi tertatih-tatih.

Saya tidak dapat menemukan utas yang ia sebutkan. Sekarang, saya dapat memahami bahwa pengenalan tipe fungsi struktural mungkin menyiratkan komplikasi tertentu dalam sistem tipe kebanyakan Java, apa yang saya tidak bisa mengerti adalah bagaimana perbedaan tipe SAM berbeda dalam hal reifikasi.

Bukankah mereka berdua mengalami masalah reifikasi yang sama? Apakah ada yang mengerti bagaimana tipe fungsi berbeda dari tipe SAM yang diparameterisasi dalam hal reifikasi?

Dalam komentar lain Goetz mengatakan:

Ada dua pendekatan dasar untuk mengetik: nominal dan struktural. Identitas nominal didasarkan pada namanya; identitas tipe struktural didasarkan pada apa yang tersusun dari (seperti "tupel int, int" atau "fungsi dari int ke float".) Sebagian besar bahasa memilih sebagian besar nominal atau sebagian besar struktural; tidak ada banyak bahasa yang berhasil mencampur pengetikan nominal dan struktural kecuali "di tepinya." Java hampir seluruhnya nominal (dengan beberapa pengecualian: array adalah tipe struktural, tetapi di bagian bawah selalu ada tipe elemen nominal; generik memiliki campuran nominal dan struktural juga, dan ini sebenarnya merupakan bagian dari sumber banyak keluhan orang tentang obat generik.) Mencangkok sistem tipe struktural (tipe fungsi) ke Java ' Sistem tipe nominal berarti kompleksitas baru dan kasing tepi. Apakah manfaat tipe fungsi sepadan dengan ini?

Bagi Anda yang berpengalaman dalam implementasi sistem tipe. Apakah Anda tahu contoh kompleksitas atau kasus tepi yang ia sebutkan di sini?

Jujur saya bingung dengan tuduhan ini ketika saya menganggap bahwa bahasa pemrograman seperti Scala, yang sepenuhnya didasarkan pada JVM, memiliki dukungan untuk tipe struktural seperti fungsi dan tupel, bahkan dengan masalah reifikasi platform yang mendasarinya.

Jangan salah paham, saya tidak mengatakan bahwa tipe fungsi harus lebih baik daripada tipe SAM. Saya hanya ingin mengerti mengapa mereka mengambil keputusan ini.

edalorzo
sumber
4
"Mencangkok sistem tipe struktural (tipe fungsi) ke sistem tipe nominal Java berarti kompleksitas baru" - ini kemungkinan besar dimaksudkan sebagai kompleksitas bagi pengguna yang harus belajar lebih banyak untuk menggunakan bahasa tersebut . Sesuatu seperti Java yang sederhana dan mudah digunakan menjadi rumit dan sulit dipelajari C ++ , hal-hal seperti itu. Anggota milis mungkin dapat menyinggung kritik terhadap "gelombang besar perbaikan" sebelumnya, salah satu contoh yang menonjol adalah Java 5 sucks article oleh Clinton Begin dari MyBatis
gnat
3
"Sederhana dan mudah digunakan Java menjadi seperti rumit dan sulit dipelajari C ++": Sayangnya, satu masalah dengan bahasa pemrograman arus utama adalah mereka harus mempertahankan kompatibilitas ke belakang dan karena itu mereka cenderung menjadi terlalu kompleks. Jadi IMHO (memiliki pengalaman bertahun-tahun dengan C ++ dan Java) ada sesuatu yang benar untuk pernyataan ini. Saya sering merasa bahwa Java harus dibekukan dan bahasa baru harus dikembangkan sebagai gantinya. Tetapi Oracle tidak bisa mengambil risiko seperti itu.
Giorgio
4
@edalorzo: Seperti yang diperlihatkan Clojure, Groovy, Scala, dan bahasa lainnya, dimungkinkan untuk (1) mendefinisikan bahasa baru (2) menggunakan semua kekayaan perpustakaan dan alat yang sudah ditulis di Jawa tanpa melanggar kompatibilitas ke belakang (3) memberi Programmer Java memiliki kebebasan untuk memilih apakah mereka ingin tetap menggunakan Java, beralih ke bahasa lain, atau menggunakan keduanya. IMO, memperluas bahasa yang sudah ada tanpa batas adalah strategi untuk mempertahankan pelanggan, dengan cara yang sama seperti perusahaan ponsel perlu membuat model baru setiap saat.
Giorgio
2
Seperti yang saya pahami dari SAMbdas di Jawa , salah satu alasannya adalah bahwa akan bermasalah untuk menjaga beberapa perpustakaan (koleksi) tetap kompatibel.
Petr Pudlák
2
Posting terkait pada SO yang menghubungkan ke posting lain ini oleh Goetz .
assylias

Jawaban:

6

Pendekatan SAM sebenarnya agak mirip dengan apa yang Scala (dan C ++ 11) lakukan dengan fungsi anonim (dibuat dengan =>operator Scala atau []()sintaksis C ++ 11 (lambda)).

Pertanyaan pertama yang harus dijawab di sisi Jawa adalah apakah memiliki tipe kembalinya dari pernyataan lambda menjadi tipe primitif baru, seperti intatau byte, atau tipe objek semacam itu. Dalam Scala, ada yang tidak ada tipe primitif - bahkan integer adalah obyek dari kelas Int- dan fungsi yang tidak berbeda, menjadi objek dari kelas Function1, Function2dan sebagainya, tergantung pada jumlah argumen fungsi mengambil.

C ++ 11, ruby ​​dan python juga memiliki ekspresi lambda yang mengembalikan objek yang dapat dipanggil secara eksplisit atau implisit. Objek yang dikembalikan memiliki beberapa metode standar (seperti #callyang dapat digunakan untuk memanggilnya sebagai fungsi. C ++ 11, misalnya, menggunakan std::functiontipe yang kelebihan operator()sehingga panggilan metode panggilan objek bahkan terlihat seperti pemanggilan fungsi, secara tekstual. :-)

Di mana proposal baru untuk Java menjadi berantakan adalah dalam penggunaan pengetikan struktural untuk memungkinkan menetapkan metode seperti itu ke objek lain, seperti Comparatoryang memiliki metode utama tunggal dengan nama yang berbeda . Sementara ini secara konseptual idih dalam beberapa hal, itu tidak berarti bahwa objek yang dihasilkan dapat dikirimkan ke fungsi yang ada yang mengambil objek untuk mewakili callback, pembanding, dan seterusnya, dan berharap untuk dapat memanggil didefinisikan dengan baik tunggal metode seperti #compareatau #callback. Trik C ++ untuk mengesampingkan secara operator()rapi menghindari masalah ini bahkan sebelum C ++ 11, karena semua opsi panggilan balik seperti itu dapat dipanggil dengan cara yang sama, dan dengan demikian STL tidak memerlukan penyesuaian untuk memungkinkan C ++ 11 lambdas digunakan dengansortdan seterusnya. Java, tidak pernah menggunakan penamaan standar untuk objek seperti itu di masa lalu (mungkin karena tidak ada trik seperti overloading operator membuat pendekatan tunggal jelas), tidak begitu beruntung, jadi peretasan ini mencegah mereka dari harus mengubah banyak API yang ada .

jimwise
sumber
1
Ironisnya, masalah jika memiliki segudang jenis berbeda, yang tidak kompatibel, semua yang mewakili semacam "fungsi-seperti hal" dapat dengan rapi dihindari dengan menambahkan jenis fungsi standar ke perpustakaan sejak awal, independen dari memiliki sintaks literal aktual untuk membangunnya. Jika ada java.util.Function2<T1, T2, R>di Java 1.0, maka tidak akan ada Comparatorantarmuka, sebaliknya semua metode tersebut akan mengambil Function2<T1, T2, int>. (Ya, akan ada seluruh petak antarmuka seperti Function2TT_int<T1, T2>karena primitif, tetapi Anda mengerti maksud saya.)
Jörg W Mittag