Apa yang membuat operator Scala kelebihan muatan “baik”, tetapi C ++ “buruk”?

155

Overloading operator dalam C ++ dianggap oleh banyak orang sebagai A Bad Thing (tm), dan kesalahan tidak diulang dalam bahasa yang lebih baru. Tentu saja, itu adalah salah satu fitur yang secara khusus dijatuhkan ketika mendesain Java.

Sekarang saya sudah mulai membaca di Scala, saya menemukan bahwa ia memiliki apa yang tampak seperti overloading operator (walaupun secara teknis ia tidak memiliki overloading operator karena tidak memiliki operator, hanya fungsi). Namun, sepertinya tidak akan berbeda secara kualitatif dengan overloading operator di C ++, di mana seingat saya operator didefinisikan sebagai fungsi khusus.

Jadi pertanyaan saya adalah apa yang membuat ide untuk mendefinisikan "+" di Scala ide yang lebih baik daripada di C ++?

skaffman
sumber
27
Baik C ++ bukan Scala didefinisikan oleh konsensus universal di antara semua programmer. Saya tidak berpikir ada kontradiksi antara fakta bahwa beberapa orang mengeluh tentang C ++, dan fakta bahwa beberapa orang tidak mengeluh tentang Scala.
Steve Jessop
16
Tidak ada yang buruk tentang kelebihan operator di C ++.
Puppy
5
Ini bukan hal baru, tetapi cara saya mempertahankan C ++ ketika operator kelebihan dan fitur "canggih" lainnya dipertanyakan adalah sederhana: C ++ memberi kita semua kekuatan untuk menggunakan / menyalahgunakannya sesuai keinginan kita. Saya selalu menyukai bagaimana kita dianggap kompeten dan otonom dan tidak perlu keputusan seperti ini dibuat untuk kita.
Elliott
Scala dirancang seperti beberapa dekade setelah c ++. Ternyata orang di belakangnya sangat ahli dalam hal bahasa pemrograman. Tidak ada hal buruk tentang itu, jika Anda tetap menggunakan c ++ atau Scala selama 100 tahun, menjadi jelas bahwa mungkin keduanya buruk! Menjadi bias tampaknya sudah menjadi sifat kita, tetapi kita bisa melawannya, lihat saja sejarah teknologi, semuanya menjadi usang.
Nader Ghanbari

Jawaban:

242

C ++ mewarisi operator biru yang sebenarnya dari C. Maksud saya bahwa "+" di 6 + 4 sangat istimewa. Anda tidak bisa, misalnya, mendapatkan pointer ke fungsi + itu.

Scala di sisi lain tidak memiliki operator seperti itu. Itu hanya memiliki fleksibilitas besar dalam mendefinisikan nama metode ditambah sedikit dibangun diutamakan untuk simbol non-kata. Jadi secara teknis Scala tidak memiliki kelebihan operator.

Apa pun yang Anda ingin menyebutnya, kelebihan operator pada dasarnya tidak buruk, bahkan di C ++. Masalahnya adalah ketika programmer buruk menyalahgunakannya. Tapi sejujurnya, saya berpendapat bahwa menghilangkan kemampuan programmer untuk menyalahgunakan kelebihan operator tidak akan membuat Anda memperbaiki semua hal yang bisa disalahgunakan oleh programmer. Jawaban sebenarnya adalah mentoring. http://james-iry.blogspot.com/2009/03/operator-overloading-ad-absurdum.html

Tidak ada yang kurang, ada perbedaan antara overloading operator C ++ dan metode penamaan yang fleksibel Scala yang, IMHO, membuat Scala lebih baik dan lebih kasar.

Di C ++ satu-satunya cara untuk mendapatkan notasi in-fix adalah menggunakan operator. Kalau tidak, Anda harus menggunakan object.message (argumen) atau pointer-> messsage (argumen) atau fungsi (argument1, argument2). Jadi jika Anda ingin gaya DSLish tertentu untuk kode Anda maka ada tekanan untuk menggunakan operator.

Di Scala Anda bisa mendapatkan notasi infiks dengan mengirim pesan apa pun. "argumen pesan objek" sangat oke, yang berarti Anda tidak perlu menggunakan simbol non-kata hanya untuk mendapatkan notasi infiks.

Kelebihan operator C ++ terbatas pada dasarnya operator C. Dikombinasikan dengan batasan bahwa hanya operator yang dapat menggunakan infiks yang menekan orang untuk mencoba memetakan berbagai konsep yang tidak terkait ke simbol yang relatif sedikit seperti "+" dan ">>"

Scala memungkinkan sejumlah besar simbol non-kata yang valid sebagai nama metode. Sebagai contoh, saya punya DSL Prolog-ish tertanam di mana Anda dapat menulis

female('jane)!         // jane is female
parent('jane,'john)!   // jane is john's parent
parent('jane, 'wendy)! // jane is wendy's parent

mother('Mother, 'Child) :- parent('Mother, 'Child) & female('Mother) //'// a mother of a child is the child's parent and is female

mother('X, 'john)?  // find john's mother
mother('jane, 'X)?  // find's all of jane's children

Simbol: -,!,?, Dan & didefinisikan sebagai metode biasa. Dalam C ++ saja & akan valid sehingga upaya untuk memetakan DSL ini ke C ++ akan memerlukan beberapa simbol yang sudah membangkitkan konsep yang sangat berbeda.

Tentu saja, ini juga membuka Scala untuk jenis penyalahgunaan lainnya. Di Scala, Anda dapat memberi nama metode $! & ^% Jika mau.

Untuk bahasa lain yang, seperti Scala, fleksibel dalam penggunaan fungsi non-kata dan nama metode lihat Smalltalk di mana, seperti Scala, setiap "operator" hanyalah metode lain dan Haskell yang memungkinkan pemrogram untuk menentukan prioritas dan perbaikan dari nama fleksibel. fungsi.

James Iry
sumber
Terakhir saya periksa, 3. operator + (5) bekerja. Saya sangat terkejut bahwa & (3.operator +) tidak.
Joshua
Anda bisa misalnya melakukan menegaskan (perempuan ("jane")) di c ++. Itu tidak akan membingungkan sama sekali - mengangguk kembali ke posting james-iry tentang itu bukan karena operator + adalah Hal yang Buruk, tetapi programmer bodoh.
Pukul
1
@Joshua int main() {return (3).operator+(5);}menghasilkanerror: request for member ‘operator+’ in ‘3’, which is of non-class type ‘int’
zildjohn01
Itu omong kosong sombong: "kelebihan operator tidak buruk, bahkan di C ++. Masalahnya adalah ketika programmer buruk menyalahgunakannya." Jika sesuatu mudah disalahgunakan dengan sedikit manfaat dari menggunakannya, hasil keseluruhan adalah bahwa orang berikutnya yang menjaga kode Anda akan kehilangan produktivitas dalam menguraikan bagian aneh dari kode Anda. Sebaliknya: jawaban yang sangat informatif dan ditulis dengan baik.
Jukka Dahlbom
@JukkaDahlbom Keberadaan smart pointer membuat manfaatnya besar. Dan kemudian Anda memiliki lambdas, tipe angka yang ditentukan pengguna, tipe interval ...
Alexey Romanov
66

Overloading operator dalam C ++ dianggap oleh banyak orang sebagai A Bad Thing (tm)

Hanya oleh orang bebal. Ini benar-benar diperlukan dalam bahasa seperti C ++, dan terlihat bahwa bahasa lain yang mulai mengambil pandangan "purist", telah menambahkannya begitu desainer mereka mengetahui betapa perlunya itu.


sumber
30
Saya sebenarnya setuju dengan Neil. Kelebihan operator sangat penting jika Anda ingin menampilkan variabel / konstanta / objek / instance sebagai entitas aljabar ... dan minta orang memahami interaksi mereka secara matematis - yang seharusnya merupakan cara kerja pemrograman IMHO.
Massa
16
+1, Operator overloading di C ++ bagus. Misalnya itu membuat matematika vektor jauh lebih bersih. Seperti halnya banyak fitur C ++, Anda harus menggunakan daya dengan hati-hati.
John Smith
7
@Kristo Karena C ++ menggunakan nilai yang harus ditetapkan dan disalin. Penting untuk memiliki kontrol atas hal itu, sehingga Anda harus dapat menentukan operator penugasan untuk jenis tertentu, minimal.
7
@ Kristo: karena salah satu niat C ++ adalah untuk memungkinkan tipe yang ditentukan pengguna untuk melakukan semua yang dilakukan tipe builtin (walaupun mereka diperlakukan secara berbeda dalam beberapa konteks seperti konversi implisit). Jika Anda ingin menerapkan integer 27-bit, maka Anda bisa, dan menggunakannya akan sama seperti menggunakan int. Tanpa kelebihan operator, tidak mungkin menggunakan UDT dengan sintaks yang sama dengan tipe bawaan, dan karenanya bahasa yang dihasilkan tidak akan "seperti C ++" dalam pengertian ini.
Steve Jessop
8
"that way kebohongan gila" - bahkan lebih buruk, demikian kebohongan std :: vector <bool>!
Steve Jessop
42

Overloading operator tidak pernah secara universal dianggap sebagai ide buruk di C ++ - hanya penyalahgunaan operator overloading dianggap sebagai ide yang buruk. Seseorang tidak benar-benar membutuhkan operator kelebihan dalam bahasa karena mereka dapat disimulasikan dengan lebih banyak panggilan fungsi verbose. Menghindari overloading operator di Jawa membuat implementasi dan spesifikasi Java sedikit lebih sederhana dan memaksa programmer untuk tidak menyalahgunakan operator. Ada beberapa perdebatan di komunitas Jawa tentang memperkenalkan kelebihan operator.

Keuntungan dan kerugian kelebihan operator di Scala sama dengan di C ++ - Anda dapat menulis lebih banyak kode alami jika Anda menggunakan operator yang berlebihan secara tepat - dan kode yang lebih samar dan samar jika tidak.

FYI: Operator tidak didefinisikan sebagai fungsi khusus dalam C ++, mereka berperilaku seperti fungsi lainnya - meskipun ada beberapa perbedaan dalam pencarian nama, apakah mereka perlu menjadi fungsi anggota, dan fakta bahwa mereka dapat dipanggil dengan dua cara: 1 ) sintaksis operator, dan 2) sintaksis fungsi-operator-id.

Faisal Vali
sumber
"Seseorang tidak benar-benar membutuhkan operator kelebihan dalam bahasa karena mereka dapat disimulasikan dengan lebih banyak panggilan fungsi verbose." Seseorang bahkan tidak benar-benar membutuhkan operator di bawah logika itu. Kenapa tidak pakai saja add(2, multiply(5, 3))?
Joe Z.
Ini lebih merupakan kasus yang cocok dengan notasi yang biasa digunakan. Pertimbangkan matematikawan dan fisikawan, mereka dapat memahami dan menggunakan pustaka C ++ yang menyediakan lebih banyak operator secara lebih mudah. Mereka lebih suka berkonsentrasi pada persamaan daripada bahasa pemrograman.
Phil Wright
19

Artikel ini - " Warisan Positif C ++ dan Java " - menjawab pertanyaan Anda secara langsung.

"C ++ memiliki alokasi tumpukan dan alokasi tumpukan dan Anda harus membebani operator Anda untuk menangani semua situasi dan tidak menyebabkan kebocoran memori. Memang sulit. Java, bagaimanapun, memiliki mekanisme alokasi penyimpanan tunggal dan pengumpul sampah, yang membuat operator kelebihan beban sepele". ..

Java keliru (menurut penulis) menghilangkan overloading operator karena rumit dalam C ++, tetapi lupa mengapa (atau tidak menyadari bahwa itu tidak berlaku untuk Java).

Untungnya, bahasa tingkat yang lebih tinggi seperti Scala memberikan opsi kepada pengembang, sementara masih berjalan pada JVM yang sama.

jmanning2k
sumber
14
Eckel adalah satu-satunya sumber yang pernah saya lihat untuk gagasan bahwa kelebihan operator dibuang dari Jawa karena komplikasi dalam C ++ dan dia tidak mengatakan apa sumbernya. Saya akan diskon itu. Semua sumber lain yang saya katakan bahwa itu dibuang karena berpotensi penyalahgunaan. Lihat gotw.ca/publications/c_family_interview.htm dan newt.com/wohler/articles/james-gosling-ramblings-1.html . Cukup cari halaman mereka untuk "operator overloading."
James Iry
9

Tidak ada yang salah dengan kelebihan operator. Bahkan, ada yang salah dengan tidak memiliki operator kelebihan untuk tipe numerik. (Lihatlah beberapa kode Java yang menggunakan BigInteger dan BigDecimal.)

C ++ memiliki tradisi menyalahgunakan fitur. Contoh yang sering dikutip adalah bahwa operator bitshift kelebihan beban untuk melakukan I / O.

dan04
sumber
<< dan >> operator secara visual menunjukkan cara transfer, mereka dimaksudkan untuk melakukan I / O, itu bukan penyalahgunaan, itu dari perpustakaan standar dan hal praktis. Lihat saja "cin >> sesuatu", apa yang terjadi di mana? Dari cin, ke sesuatu, jelas.
peenut
7
@peenut: Tapi penggunaan aslinya sedikit berubah. "Perpustakaan standar" menggunakan operator dengan cara yang benar-benar mengacaukan definisi asli.
Joe Z.
1
Saya yakin saya telah membaca di suatu tempat bahwa Bjarne Stroustrup (pencipta C ++) bereksperimen dengan menggunakan =alih-alih <<dan >>pada hari-hari awal C ++, tetapi mengalami masalah karena tidak memiliki prioritas operator yang tepat (yaitu apakah ia mencari argumen di sebelah kiri atau kanan terlebih dahulu). Jadi tangannya agak terikat tentang apa yang bisa dia gunakan.
Phil Wright
8

Secara umum itu bukan hal yang buruk.
Bahasa baru seperti C # juga memiliki kelebihan operator.

Itu adalah penyalahgunaan operator overloading yang merupakan hal yang buruk.

Tetapi ada juga masalah dengan overloading operator sebagaimana didefinisikan dalam C ++. Karena operator kelebihan beban hanyalah gula sintaksis untuk pemanggilan metode, mereka berperilaku seperti metode. Di sisi lain, operator bawaan normal tidak berperilaku seperti metode. Ketidakkonsistenan ini dapat menyebabkan masalah.

Dari atas operator kepala saya ||dan &&.
Versi bawaannya adalah operator pintasan. Ini tidak benar untuk versi kelebihan beban dan telah menyebabkan beberapa masalah.

Fakta bahwa + - * / semua mengembalikan jenis yang sama dengan yang mereka operasikan (setelah promosi operator)
Versi kelebihan beban dapat mengembalikan apa pun (Di sinilah penyalahgunaan terjadi, Jika operator Anda mulai mengembalikan beberapa jenis arbiter yang tidak diharapkan pengguna tidak diharapkan oleh pengguna) semuanya turun bukit).

Martin York
sumber
8

Overloading operator bukanlah sesuatu yang benar-benar Anda "butuhkan" sangat sering, tetapi ketika menggunakan Java, jika Anda mencapai titik di mana Anda benar-benar membutuhkannya, itu akan membuat Anda ingin merobek kuku Anda hanya agar Anda memiliki alasan untuk berhenti mengetik .

Kode yang baru saja Anda temukan melimpah? Yup, Anda harus mengetik ulang keseluruhan untuk membuatnya bekerja dengan BigInteger. Tidak ada yang lebih membuat frustrasi bahwa harus menemukan kembali roda hanya untuk mengubah jenis variabel.


sumber
6

Guy Steele berpendapat bahwa overloading operator harus di Jawa juga, dalam pidatonya "Menumbuhkan bahasa" - ada video dan transkripsi, dan itu benar-benar pidato yang luar biasa. Anda akan bertanya-tanya apa yang dia bicarakan untuk beberapa halaman pertama, tetapi jika Anda terus membaca, Anda akan melihat intinya dan mencapai pencerahan. Dan fakta bahwa dia bisa melakukan pidato seperti itu sama sekali juga luar biasa.

Pada saat yang sama, ceramah ini menginspirasi banyak penelitian mendasar, mungkin termasuk Scala - ini adalah salah satu makalah yang harus dibaca semua orang untuk bekerja di lapangan.

Kembali ke titik, contoh-contohnya sebagian besar tentang kelas numerik (seperti BigInteger, dan beberapa hal aneh), tetapi itu tidak penting.

Memang benar, bahwa penyalahgunaan overloading operator dapat menyebabkan hasil yang mengerikan, dan bahkan penggunaan yang tepat dapat memperumit masalah, jika Anda mencoba membaca kode tanpa mempelajari sedikit perpustakaan yang digunakan. Tapi apakah itu ide yang bagus? OTOH, bukankah perpustakaan seperti itu harus mencoba memasukkan lembar contekan operator untuk operator mereka?

Blaisorblade
sumber
4

Saya percaya SETIAP jawaban terjawab ini. Di C ++ Anda bisa membebani operator semau Anda, tetapi Anda tidak bisa memengaruhi prioritas yang telah mereka evaluasi. Scala tidak memiliki masalah ini, IIRC.

Adapun itu menjadi ide yang buruk, selain masalah diutamakan, orang-orang datang dengan makna yang sangat gila untuk operator, dan jarang membantu keterbacaan. Perpustakaan scala sangat buruk untuk ini, simbol konyol yang harus Anda hafal setiap kali, dengan pengelola perpustakaan menempelkan kepala mereka di pasir berkata, 'Anda hanya perlu mempelajarinya sekali saja'. Hebat, sekarang saya perlu belajar beberapa sintaksis samar 'pintar' penulis * jumlah perpustakaan yang saya ingin gunakan. Tidak akan terlalu buruk jika ada konvensi SELALU menyediakan versi melek huruf dari operator.

Saem
sumber
1
Scala juga telah memperbaiki prioritas operator, bukan?
skaffman
Saya percaya ada, tapi jauh lebih datar. Lebih tepatnya, Scala memiliki lebih sedikit periode operator. +, -, * adalah metode, bukan operator, IIRC. Itulah sebabnya 2 + 3 * 2, bukan 8, itu 10.
Saem
7
Scala memiliki sistem yang diutamakan berdasarkan karakter pertama dari simbol. scala> 2 + 3 * 2 res0: Int = 8
James Iry
3

Overloading operator bukanlah penemuan C ++ - itu berasal dari Algol IIRC dan bahkan Gosling tidak mengklaim itu adalah ide yang buruk secara umum.

Nemanja Trifunovic
sumber
Tentu, tapi itu dalam inkarnasi C ++ bahwa ia mendapat kesan buruk yang umum.
skaffman
5
Apa yang Anda maksudkan dengan "kesan tidak bersahabat"? Kebanyakan orang yang saya kenal menggunakan bahasa yang mendukung overloading operator (C ++, C #) dan saya belum pernah mendengar keluhan.
Nemanja Trifunovic
Saya berbicara dari pengalaman saya yang lama dengan pra-ANSI C ++, dan saya tentu ingat ketidaksukaan yang umum terhadap mereka. Mungkin situasinya membaik dengan ANSI C ++, atau orang-orang baru belajar bagaimana tidak menyalahgunakannya.
skaffman
1
Berbicara sebagai seseorang yang telah menggunakan C ++ sejak hari-hari pertama (pertengahan tahun 80-an), saya dapat meyakinkan Anda bahwa penerapan standar ISO tidak berdampak pada prasangka masyarakat tentang kelebihan operator.
3

Satu-satunya hal yang diketahui salah dalam C ++ adalah kurangnya kemampuan untuk membebani [] = sebagai operator terpisah. Ini bisa sulit untuk diterapkan dalam kompiler C ++ untuk apa yang mungkin bukan alasan yang jelas tetapi banyak yang sepadan.

Joshua
sumber
2

Seperti yang ditunjukkan oleh jawaban lain; Operator overloading itu sendiri tidak selalu buruk. Apa yang buruk ketika digunakan dengan cara yang membuat kode yang dihasilkan tidak jelas. Umumnya ketika menggunakan mereka, Anda perlu membuat mereka melakukan hal yang paling tidak mengejutkan (memiliki divisi operator + do akan menyebabkan masalah untuk penggunaan kelas rasional) atau seperti yang dikatakan Scott Meyers:

Klien sudah tahu bagaimana tipe seperti int berperilaku, jadi Anda harus berusaha agar tipe Anda berperilaku dengan cara yang sama kapan saja masuk akal ... Ketika ragu, lakukan seperti yang dilakukan int . (Dari Efektif C ++ edisi ketiga item 18)

Sekarang beberapa orang telah mengambil kelebihan operator ke ekstrim dengan hal-hal seperti boost :: spirit . Pada level ini Anda tidak tahu bagaimana ini diterapkan tetapi itu membuat sintaks yang menarik untuk mendapatkan apa yang Anda inginkan. Saya tidak yakin apakah ini baik atau buruk. Tampaknya bagus, tetapi saya belum menggunakannya.

Matt Price
sumber
Saya tidak berdebat atau menentang operator kelebihan beban di sini, saya tidak mencari orang untuk membenarkan mereka.
skaffman
Sprint tidak mendekati contoh terburuk yang pernah saya temui - Anda harus melihat apa yang dibangun oleh pangkalan data RogueWave!
Saya setuju bahwa Spirit menyalahgunakan operator, tetapi saya tidak bisa memikirkan cara yang lebih baik untuk melakukannya.
Zifre
1
Saya tidak berpikir roh cukup menyalahgunakan operator, tetapi mendorongnya. Saya setuju benar-benar tidak ada cara lain untuk melakukannya. Ini pada dasarnya menciptakan DSL dalam sintaks C ++. Sangat jauh dari apa yang dirancang untuk dilakukan oleh C ++. Ya, ada contoh yang jauh lebih buruk :) Secara umum saya menggunakannya jika perlu. Sebagian besar hanya operator streaming untuk memudahkan debugging \ logging. Dan bahkan di sana hanya gula yang meneruskan metode yang diterapkan di kelas.
Harga Matt
1
Ini pertanyaan rasa; tetapi parser combinator libraries, dalam bahasa-bahasa fungsional, membebani operator dengan cara yang sangat mirip dengan Spirit, dan tidak ada yang membantah hal itu. Ada banyak alasan teknis mengapa mereka lebih baik - Google untuk "bahasa khusus domain tertanam" untuk menemukan banyak makalah yang menjelaskannya dari sudut pandang umum, dan Google untuk "scala parser combinator" untuk contoh praktis dalam kasus ini. Memang benar bahwa dalam bahasa fungsional sintaks yang dihasilkan seringkali lebih baik - misalnya, Anda tidak perlu mengubah arti >> untuk parser gabungan.
Blaisorblade
2

Saya belum pernah melihat artikel yang mengklaim bahwa overloading operator C ++ buruk.

Operator yang ditentukan pengguna memungkinkan tingkat ekspresivitas dan kegunaan yang lebih tinggi dan mudah bagi pengguna bahasa.

Paul Nathan
sumber
1

Namun, sepertinya tidak akan berbeda secara kualitatif dengan overloading operator di C ++, di mana seingat saya operator didefinisikan sebagai fungsi khusus.

AFAIK, Tidak ada yang istimewa dalam fungsi operator dibandingkan dengan fungsi anggota "normal". Tentu saja Anda hanya memiliki satu set operator tertentu yang dapat kelebihan beban, tetapi itu tidak membuat mereka sangat istimewa.

John Smith
sumber