Apakah ekspresi lambda lebih dari sekadar kelas batin anonim dengan metode tunggal?

40

Ada hype baru dengan ekspresi lambda yang telah lama ditunggu di Jawa 8; setiap 3 hari artikel lain muncul dengan mereka tentang betapa kerennya mereka.

Sejauh yang saya mengerti ekspresi lambda tidak lebih dari kelas batin anonim dengan metode tunggal (setidaknya pada level byte-code). Selain itu ia datang dengan fitur bagus lain - inferensi tipe tapi saya percaya ini setara dapat dicapai dengan obat generik pada tingkat tertentu (tentu saja tidak dengan cara yang rapi seperti dengan ekspresi lambda).

Mengetahui hal ini, apakah ekspresi lambda akan membawa sesuatu yang lebih dari sekadar sugaring sintaksis di Jawa? Bisakah saya membuat kelas yang lebih kuat dan fleksibel atau konstruksi berorientasi objek lainnya dengan ekspresi lambda yang tidak mungkin dibangun dengan fitur bahasa saat ini?

m3th0dman
sumber
30
Ketika suatu bahasa selesai-turing, setiap fitur yang ditambahkan secara teoritis dapat digambarkan sebagai "gula sintaksis".
Philipp
34
@ Pilip: Itu salah. Ciri khas dari sintaksis gula adalah bahwa keinginan murni murni lokal dan tidak mengubah struktur global program. Ada banyak fitur yang tidak dapat diimplementasikan hanya dengan transformasi lokal. Misalnya, jika Anda mengambil bahasa hipotetis yang identik dengan Jawa tetapi dengan panggilan ekor yang tepat, tidak mungkin untuk mendeskripsikan panggilan ekor ke Jawa "murni" tanpa mengubah seluruh program secara global.
Jörg W Mittag
2
@ Pilhipp: Sayangnya hanya ada satu upvote untuk komentar, kalau tidak saya akan komentar Joerg 1000 kali. Tidak, itu salah bahwa fitur apa pun dapat digambarkan sebagai gula sintaksis. Gula sintaksis tidak menambahkan semantik baru. Bahkan, AFAIK lambda Jawa yang diusulkan BUKAN gula sintaksis untuk kelas batin anonim khusus karena mereka memiliki semantik yang berbeda.
Giorgio
1
@Iorgio: dan apa perbedaan semantik yang mereka miliki?
user102008
2
@Giorgio: Ya, tetapi konversi thismenjadi menjadi OuterClass.thisbagian dari proses de-sugaring ekspresi lambda ke kelas anonim.
user102008

Jawaban:

47

tl; dr: walaupun sebagian besar berupa gula sintaksis, sintaksis yang lebih baik membuat banyak hal praktis yang digunakan untuk mengakhiri garis kawat gigi dan tanda kurung yang tak terbaca.

Yah, sebenarnya sebaliknya karena lambda jauh lebih tua dari Jawa. Kelas batin anonim dengan metode tunggal adalah Jawa yang paling dekat datang ke lambdas. Ini perkiraan yang "cukup baik" untuk beberapa waktu, tetapi memiliki sintaks yang sangat buruk.

Di permukaan, lambda Jawa 8 tampaknya tidak lebih dari gula sintaksis, tetapi ketika Anda melihat di bawah permukaan, Anda melihat banyak abstraksi yang menarik. Misalnya spec JVM memperlakukan lambda sangat berbeda dari objek "true", dan sementara Anda dapat menanganinya seolah-olah mereka di mana objek, JVM tidak diharuskan untuk mengimplementasikannya seperti itu.

Tetapi sementara semua tipuan teknis itu menarik dan relevan (karena memungkinkan optimasi masa depan di JVM!), Manfaat sebenarnya adalah "hanya" bagian gula sintaksis.

Apa yang lebih mudah dibaca:

myCollection.map(new Mapper<String,String>() {
  public String map(String input) {
    return new StringBuilder(input).reverse().toString();
  }
});

atau:

myCollection.map(element -> new StringBuilder(element).reverse().toString());

atau (menggunakan pegangan metode alih-alih lambda):

myCollection.map(String::toUpperCase);

Fakta bahwa Anda akhirnya dapat mengungkapkan dengan cara ringkas yang sebelumnya akan menjadi 5 baris kode (yang 3 sangat membosankan) membawa perubahan nyata dari apa yang praktis (tetapi bukan dari apa yang mungkin, diberikan).

Joachim Sauer
sumber
1
Saya sepenuhnya setuju dengan bagian sugaring sintaksis; pertanyaan saya adalah tentang konstruksi berorientasi objek baru hanya mungkin dengan ekspresi lambda; lagipula Java adalah bahasa berorientasi objek. Pikirkan dibandingkan dengan obat generik, dan bagaimana mereka membeli banyak fleksibilitas di Jawa, fleksibilitas tidak dapat dicapai tanpa mereka.
m3th0dman
7
@ m3th0dman: sebenarnya generik tidak menambahkan kemampuan baru. A Listbisa memegang objek apa pun, List<String>bisa "hanya" memegang string. Generik menambahkan batasan (dan opsi untuk memformalkan pembatasan!), Bukan tambahan daya. Hampir semuanya sejak Java 1.1 adalah gula sintaksis. Dan itu belum tentu hal yang buruk.
Joachim Sauer
3
@ m3th0dman: Sebenarnya generik tidak menambahkan kemampuan baru, karena di Jawa mereka hanya gula sintaksis. A List<String>adalah hanya Listdengan pemain yang Stringditambahkan di sekitar beberapa nilai kembali. Namun demikian mereka sangat berguna dan membuat bahasa lebih nyaman untuk menulis. Lambdas adalah kasus serupa.
Jan Hudec
3
Sebenarnya ini jauh lebih dari sekadar gula sintaksis. Sebagian besar fungsi diimplementasikan sebagai warga negara kelas satu di JVM melalui penggunaan bytecode invokedynamic + beberapa kemajuan yang lumayan besar ke sistem inferensi Jenis. Itu tidak diimplementasikan sebagai kelas batin anonim.
Martijn Verburg
1
@ JanHudec: yah, mereka sedikit lebih dari gula sintaksis, karena kompiler sebenarnya menghormatinya. The runtime tidak peduli tentang mereka, itu benar.
Joachim Sauer
14

Untuk Java, ya, itu tidak lebih dari cara yang lebih baik untuk menciptakan kelas batin anonim. Ini karena keputusan mendasar di java bahwa setiap bit kode byte harus hidup dalam kelas tertentu, yang tidak dapat diubah sekarang setelah beberapa dekade kode legasi dipertimbangkan.

Namun, bukan itu yang dimaksud dengan ekspresi lambda. Dalam formalisme di mana mereka adalah konsep asli dan bukan lompatan langsung, lambda adalah blok bangunan fundamental; sintaksis mereka dan sikap orang terhadap mereka sangat berbeda. Contoh fungsi rekursif anonim yang dibuat murni dari lambdas dalam Struktur dan Interpretasi Program Komputer mampu mengubah seluruh konsepsi komputasi Anda. (Namun, saya cukup yakin bahwa cara belajar program hanya untuk esoteris yang pernah menjadi kisah sukses arus utama.)

Kilian Foth
sumber
1
Belajar bahwa segala sesuatu dapat diimplementasikan dalam hal lambda sangat instruktif dan tidak "esoteris" menurut pendapat saya. (Namun, saya kira sebagian besar "coders" tidak peduli dengan teori CS yang menarik.) Itu tidak berarti bahwa lambdas adalah istimewa; itu hanya berarti bahwa lambda adalah satu jenis konstruksi universal. Ada yang lain, seperti combinator SKI. Lambdas adalah blok bangunan mendasar dalam paradigma fungsional, tetapi mungkin sesuatu yang lain bisa menjadi fundamental dalam paradigma lain.
user102008
+1 untuk "lompatan langsung ikut-ikutan": Saya sering bertanya-tanya mengapa beberapa bahasa terus berubah untuk meniru bahasa populer lainnya dan mengapa pemrogram bertahan. Saya suka lambdas dan banyak menggunakannya di Scala, Lisp, Haskell, tetapi di Jawa atau C ++ mereka merasa seperti baru saja melesat ke bahasa hanya karena mereka menjadi populer di bahasa lain.
Giorgio
2

Ya, itu hanya gula sintaksis, dalam arti bahwa di mana pun Anda menulis lambda, Anda dapat menulis ulang ekspresi itu sebagai ekspresi kelas batin anonim dengan satu metode, di mana kelas mengimplementasikan antarmuka fungsional yang disimpulkan untuk konteks lambda, dan itu akan sama persis semantik. Dan Anda dapat melakukan ini hanya dengan mengganti ekspresi lambda dengan ekspresi kelas anonim, tanpa mengubah ekspresi atau baris kode lainnya.

pengguna102008
sumber
1
mengapa downvote? apa yang saya katakan sepenuhnya benar
user102008
Apa yang Anda tulis terdengar proposal yang masuk akal untuk lambda Jawa tetapi proposal ini dibuang demi yang lain ( doanduyhai.wordpress.com/2012/07/12/… ).
Giorgio
1
@Iorgio: Saya tidak "mengusulkan" apa pun. Apa, tepatnya, apakah Anda tidak setuju dengan apa yang saya katakan? Ya, bagian dalam ekspresi akan terlihat berbeda, misalnya kita akan menambahkan metode, dan ya, thisperlu dikonversi OuterClass.this. Itu tidak bertentangan dengan apa yang saya katakan - setiap ekspresi lambda dapat dikonversi menjadi ekspresi kelas anonim yang setara secara semantis tanpa mengubah apa pun di luar ekspresi itu . Saya tidak mengatakan bahwa bagian dalamnya tidak akan berubah.
user102008
3
Apa yang Anda katakan salah. Semantik dari lambda dan kelas batin tidak persis sama (meskipun mereka serupa). Dari atas kepala saya, makna makna dari perubahan ini ; dan setiap kelas batin selalu menghasilkan contoh baru dari suatu objek, sedangkan lambda mungkin atau mungkin tidak.
Stuart Marks
1
@StuartMarks: Tidak, Anda tidak membaca jawaban saya. Saya tidak mengatakan bahwa masing-masing dari mereka dapat melakukan semua hal yang lain lakukan. Saya mengatakan bahwa lambda memiliki kelas anonim yang setara yang secara semantik sama. Seperti yang sudah saya katakan di komentar, thisdi lambda adalah bagian dari gula sintaksis, dan tidak ada perbedaan dalam semantik. Dan tentang perbedaan dalam implementasi, implementasi! = Semantik. Tentang perbedaan identitas objek; identitas objek sangat tangensial dengan fungsi lambdas; tidak ada yang memeriksa identitas objek kelas lambdas / anon karena itu tidak berguna.
user102008
1

Joachim Sauer sudah melakukan pekerjaan dengan baik menjawab pertanyaan Anda tetapi hanya mengisyaratkan sesuatu yang saya anggap penting. Karena Lambdas bukan kelas, mereka juga tidak dikompilasi. Semua kelas dalam anonim menghasilkan pembuatan file .class yang pada gilirannya harus dimuat oleh ClassLoader. Jadi menggunakan Lambdas bukan hanya membuat kode Anda lebih indah, tetapi juga mengurangi ukuran kode kompilasi Anda, jejak memori ClassLoader Anda, dan waktu yang diperlukan untuk mentransfer bit dari hard drive Anda.

Christoph Grimmer-Dietrich
sumber
-1

Tidak, mereka bukan.

Cara lain untuk mengatakannya adalah lambda adalah cara yang tidak berorientasi objek, namun ringkas, untuk mencapai hal yang sama dengan yang dicapai oleh kelas anonim atau, preferensi saya, kelas batin dengan cara berorientasi objek.

Guido Anselmi
sumber
1
Pemrograman fungsional dapat sepenuhnya ortogonal untuk pemrograman Berorientasi Objek (lihat: Scala dan F #). Ini berbunyi seperti pendapat seseorang yang tidak suka pemrograman fungsional pada prinsipnya.
KChaloux
1
@KChaloux - Bukan pembenci pemrograman fungsional. Jawabannya ditulis oleh seseorang yang lebih suka memiliki palu dan obeng daripada palu. Pemrograman OO adalah paradigma yang baik, seperti pemrograman fungsional. Preferensi saya dalam suatu bahasa adalah agar jelas tentang niatnya. Lambdas Saya merasa berlumpur sifat OO Jawa sebaliknya. Java tidak dirancang untuk menjadi bahasa fungsional. Manusia membutuhkan struktur untuk melakukan pekerjaan terbaiknya.
Guido Anselmi