Saya tidak mengerti argumen terhadap kelebihan operator [ditutup]

82

Saya baru saja membaca salah satu artikel Joel di mana dia berkata:

Secara umum, saya harus mengakui bahwa saya sedikit takut dengan fitur bahasa yang menyembunyikan banyak hal . Ketika Anda melihat kode

i = j * 5;

... di C Anda tahu, setidaknya, bahwa j dikalikan lima dan hasilnya disimpan di i.

Tetapi jika Anda melihat potongan kode yang sama di C ++, Anda tidak tahu apa-apa. Tidak ada. Satu-satunya cara untuk mengetahui apa yang sebenarnya terjadi di C ++ adalah untuk mengetahui apa tipe i dan j, sesuatu yang mungkin dinyatakan di tempat lain. Itu karena saya mungkin tipe yang operator*kelebihan beban dan melakukan sesuatu yang sangat lucu ketika Anda mencoba melipatgandakannya.

(Menekankan milikku.) Takut fitur bahasa yang menyembunyikan sesuatu? Bagaimana Anda bisa takut akan hal itu? Bukankah menyembunyikan sesuatu (juga dikenal sebagai abstraksi ) adalah salah satu ide kunci pemrograman berorientasi objek? Setiap kali Anda memanggil metode a.foo(b), Anda tidak tahu apa yang mungkin dilakukan. Anda harus mencari tahu jenis adan bapa, sesuatu yang mungkin dinyatakan di tempat lain. Jadi haruskah kita menyingkirkan pemrograman berorientasi objek, karena menyembunyikan terlalu banyak hal dari programmer?

Dan j * 5apa bedanya dengan j.multiply(5)yang Anda mungkin harus menulis dalam bahasa yang tidak mendukung kelebihan operator? Sekali lagi, Anda harus mencari tahu jenis jdan mengintip ke dalam multiplymetode, karena lihatlah, jmungkin dari jenis yang memiliki multiplymetode yang melakukan sesuatu yang sangat cerdas.

"Muahaha, aku seorang programmer jahat yang menyebutkan metode multiply, tetapi apa yang sebenarnya dilakukannya benar-benar tidak jelas dan tidak intuitif dan sama sekali tidak ada hubungannya dengan mengalikan hal-hal." Apakah itu skenario yang harus kita pertimbangkan ketika merancang bahasa pemrograman? Maka kita harus meninggalkan pengidentifikasi dari bahasa pemrograman dengan alasan bahwa mereka mungkin menyesatkan!

Jika Anda ingin tahu apa yang dilakukan metode, Anda dapat melihat dokumentasi atau mengintip ke dalam implementasi. Kelebihan operator hanya gula sintaksis, dan saya tidak melihat bagaimana itu mengubah permainan sama sekali.

Tolong beri tahu saya.

fredoverflow
sumber
20
+1: Ditulis dengan baik, didebat dengan baik, topik menarik dan sangat bisa diperdebatkan. Contoh cemerlang dari pertanyaan p.se.
Allon Guralnek
19
+1: Orang-orang mendengarkan Joel Spolsky karena dia menulis dengan baik dan terkenal. Tapi itu tidak membuatnya benar 100% dari waktu. Saya setuju dengan argumen Anda. Jika kita semua mengikuti logika Joel di sini, kita tidak akan pernah berhasil.
Tidak ada yang
5
Saya berpendapat bahwa i dan j dideklarasikan secara lokal sehingga Anda dapat melihat tipenya dengan cepat, atau mereka nama variabel yang sial dan harus diganti namanya dengan tepat.
Cameron MacFarland
5
+1, tapi jangan lupa bagian terbaik artikel Joel: setelah berlari maraton menuju jawaban yang benar, dia tanpa alasan yang jelas berhenti 50 kaki lebih pendek darinya. Kode yang salah seharusnya tidak hanya terlihat salah; seharusnya tidak dikompilasi.
Larry Coleman
3
@Larry: Anda dapat membuat kode yang salah gagal dikompilasi dengan mendefinisikan kelas secara tepat, jadi dalam contohnya Anda bisa memiliki SafeString dan UnsafeString di C ++, atau RowIndex dan ColumnIndex, tetapi kemudian Anda harus menggunakan operator yang berlebihan untuk membuat mereka berperilaku secara intuitif.
David Thornley

Jawaban:

32

Abstraksi 'menyembunyikan' kode sehingga Anda tidak perlu khawatir tentang cara kerja bagian dalam dan sering kali Anda tidak dapat mengubahnya, tetapi tujuannya bukan untuk mencegah Anda melihatnya. Kami hanya membuat asumsi tentang operator dan seperti kata Joel, itu bisa di mana saja. Memiliki fitur pemrograman yang mengharuskan semua operator kelebihan beban untuk didirikan di lokasi tertentu dapat membantu menemukannya, tetapi saya tidak yakin itu membuatnya lebih mudah menggunakannya.

Saya tidak melihat membuat * melakukan sesuatu yang tidak menyerupai perkalian lebih baik daripada fungsi yang disebut Get_Some_Data yang menghapus data.

JeffO
sumber
13
+1 Untuk bit 'Saya tidak melihat'. Fitur bahasa ada untuk digunakan, bukan penyalahgunaan.
Michael K
5
Namun kami memiliki <<operator yang didefinisikan pada stream yang tidak ada hubungannya dengan pergeseran bitwise, tepat di perpustakaan standar C ++.
Malcolm
operator 'bitwise shift' hanya dipanggil untuk alasan historis. Ketika diterapkan pada tipe standar, ia melakukan perubahan bitwise (dengan cara yang sama dengan + operator menambahkan angka bersamaan ketika diterapkan pada tipe numerik), namun ketika diterapkan pada tipe yang kompleks, ia dapat melakukan apa yang disukainya, selama ia membuat akal untuk tipe itu.
gbjbaanb
1
* juga digunakan untuk dereferencing (seperti yang dilakukan oleh smart pointer dan iterator); tidak jelas di mana harus menempatkan batas antara kelebihan beban baik dan buruk
martinkunev
Itu tidak akan ada di mana saja, itu akan menjadi definisi tipe j.
Andy
19

IMHO, fitur bahasa seperti overloading operator memberi programmer lebih banyak kekuatan. Dan, seperti kita semua tahu, dengan kekuatan besar datang tanggung jawab besar. Fitur yang memberi Anda lebih banyak kekuatan juga memberi Anda lebih banyak cara untuk menembak diri sendiri di kaki, dan, jelas, harus digunakan dengan bijaksana.

Sebagai contoh, masuk akal untuk membebani +atau *operator yang untuk class Matrixatau class Complex. Semua orang akan langsung tahu artinya. Di sisi lain, bagi saya fakta yang +berarti rangkaian string sama sekali tidak jelas, meskipun Java melakukan ini sebagai bagian dari bahasa, dan STL tidak untuk std::stringmenggunakan overloading operator.

Contoh lain yang baik ketika operator overloading membuat kode lebih jelas adalah smart pointer di C ++. Anda ingin pointer cerdas berperilaku seperti pointer biasa sebanyak mungkin, sehingga masuk akal untuk membebani unary *dan ->operator.

Intinya, overloading operator tidak lebih dari sekadar cara lain untuk memberi nama suatu fungsi. Dan ada aturan untuk fungsi penamaan: nama harus deskriptif, membuatnya segera jelas apa fungsinya. Aturan persis yang sama berlaku untuk overloading operator.

Dima
sumber
1
Dua kalimat terakhir Anda sampai pada inti keberatan terhadap kelebihan operator: keinginan agar semua kode segera terlihat.
Larry Coleman
2
Bukankah sudah jelas apa arti M * N, di mana M dan N bertipe Matrix?
Dima
2
@Fred: Tidak. Ada satu jenis perkalian matriks. Anda dapat mengalikan matriks mxn dengan matriks nxk dan mendapatkan matriks mxk.
Dima
1
@ FredOverflow: Ada berbagai cara untuk melipatgandakan vektor tiga dimensi, yang satu memberi Anda skalar dan yang lain memberi Anda vektor tiga dimensi yang lain, dan kelebihan beban *bagi yang lain dapat menyebabkan kebingungan. Bisa dibilang Anda bisa menggunakan operator*()untuk produk titik dan produk operator%()silang, tapi saya tidak akan melakukannya untuk perpustakaan penggunaan umum.
David Thornley
2
@ Martin Beckett: No. C ++ tidak diperbolehkan untuk menyusun ulang A-Bsebagai B-Abaik, dan semua operator mengikuti pola itu. Meskipun selalu ada satu pengecualian: ketika kompiler dapat membuktikan itu tidak masalah, itu diperbolehkan untuk mengatur ulang semuanya.
Sjoerd
9

Di Haskell "+", "-", "*", "/" dll hanyalah fungsi (infix).

Haruskah Anda menyebutkan fungsi infix "plus" seperti pada "4 plus 2"? Mengapa tidak, jika penambahan adalah fungsi Anda. Haruskah Anda memberi nama "plus" fungsi "+"? Kenapa tidak.

Saya pikir masalah dengan apa yang disebut "operator" adalah, bahwa mereka kebanyakan menyerupai operasi matematika dan tidak ada banyak cara untuk menafsirkannya dan dengan demikian ada harapan yang tinggi tentang apa yang dilakukan oleh metode / fungsi / operator tersebut.

EDIT: membuat poin saya lebih jelas

Program Lenny
sumber
Eh, kecuali untuk apa yang diwarisi dari C, C ++ (dan itulah yang ditanyakan Fred) melakukan hal yang hampir sama. Sekarang apa pendapat Anda tentang apakah ini baik atau buruk?
sbi
@sbi Saya suka operator overloading ... operator Sebenarnya bahkan C telah kelebihan beban ... Anda dapat menggunakannya untuk int, float, long longdan apa pun. Jadi, tentang apa semua itu?
FUZxxl
@FUZxxl: Ini semua tentang operator yang ditentukan pengguna membebani operator bawaan .
sbi
1
@sbi Haskell tidak memiliki perbedaan antara builtin dan yang ditentukan pengguna . Semua operator sama. Anda bahkan dapat mengaktifkan beberapa ekstensi yang menghapus semua hal yang telah ditentukan dan membiarkan Anda menulis apa pun dari awal, termasuk semua operator.
FUZxxl
@ FUZxxl: Itu mungkin saja, tetapi mereka yang menentang operator kelebihan beban biasanya tidak menentang penggunaan built-in +untuk tipe angka built-in yang berbeda, tetapi membuat overload yang ditentukan pengguna. karenanya komentar saya.
sbi
7

Berdasarkan jawaban lain yang saya lihat, saya hanya bisa menyimpulkan bahwa keberatan sebenarnya terhadap operator kelebihan adalah keinginan untuk kode yang segera jelas.

Ini tragis karena dua alasan:

  1. Dibawa ke kesimpulan logisnya, prinsip bahwa kode harus segera jelas akan membuat kita semua masih mengkode dalam COBOL.
  2. Anda tidak belajar dari kode yang langsung terlihat jelas. Anda belajar dari kode yang masuk akal begitu Anda meluangkan waktu untuk memikirkan cara kerjanya.
Larry Coleman
sumber
Belajar dari kode tidak selalu menjadi tujuan utama. Dalam kasus seperti "fitur X sedang bermasalah, orang yang menulisnya meninggalkan perusahaan, dan Anda harus memperbaikinya ASAP", saya lebih suka memiliki kode yang segera jelas.
Errorsatz
5

Saya agak setuju.

Jika Anda menulis multiply(j,5), jbisa dari skalar atau tipe matriks, membuat multiply()lebih atau kurang kompleks, tergantung pada apa j. Namun, jika Anda meninggalkan ide kelebihan beban sama sekali, maka fungsi harus dinamai multiply_scalar()atau multiply_matrix()yang akan membuatnya jelas apa yang terjadi di bawahnya.

Ada kode di mana banyak dari kita lebih suka satu arah dan ada kode di mana kebanyakan dari kita lebih suka dengan cara lain. Sebagian besar kode, bagaimanapun, jatuh ke jalan tengah antara dua ekstrem. Apa yang Anda sukai di sana tergantung pada latar belakang dan preferensi pribadi Anda.

sbi
sumber
Poin bagus. Namun, mengabaikan kelebihan beban sama sekali tidak cocok dengan pemrograman generik ...
fredoverflow
@FredO: Tentu saja tidak. Tetapi pemrograman generik adalah semua tentang menggunakan algoritma yang sama untuk tipe yang sangat berbeda, sehingga mereka yang lebih suka multiply_matrix()tidak akan menyukai pemrograman generik juga.
sbi
2
Anda agak optimis tentang nama, bukan? Berdasarkan beberapa tempat saya pernah bekerja, saya mengharapkan nama seperti 'multiply () `dan' multiplym ()` atau mungkin real_multiply()atau lebih. Pengembang sering tidak baik dengan nama, dan operator*()setidaknya akan konsisten.
David Thornley
@ David: Ya, saya melewatkan fakta bahwa nama-nama itu mungkin buruk. Tapi kemudian kita bisa saja berasumsi bahwa operator*()mungkin melakukan sesuatu yang bodoh, jadalah makro mengevaluasi ekspresi yang melibatkan lima panggilan fungsi, dan yang lainnya. Anda kemudian tidak dapat membandingkan kedua pendekatan itu lagi. Tapi, ya, menamai semuanya itu sulit, meskipun sepadan dengan waktu yang dibutuhkan.
sbi
5
@ David: Dan karena penamaan itu sulit, nama harus dibuang dari bahasa pemrograman, kan? Terlalu mudah untuk salah paham! ;-)
fredoverflow
4

Saya melihat dua masalah dengan kelebihan operator.

  1. Overloading mengubah semantik operator, bahkan jika itu tidak dimaksudkan oleh programmer. Misalnya, ketika Anda membebani secara berlebihan &&, ||atau ,, Anda kehilangan titik urutan yang tersirat oleh varian bawaan dari operator ini (serta perilaku hubungan pendek dari operator logis). Untuk alasan ini, lebih baik untuk tidak membebani operator ini, bahkan jika bahasa memungkinkan.
  2. Beberapa orang melihat overloading operator sebagai fitur yang bagus, mereka mulai menggunakannya di mana-mana, meskipun itu bukan solusi yang tepat. Ini menyebabkan orang lain bereaksi berlebihan ke arah lain dan memperingatkan terhadap penggunaan operator yang berlebihan. Saya tidak setuju dengan kelompok mana pun, tetapi ambil jalan tengah: Kelebihan operator harus digunakan dengan hemat dan hanya jika
    • operator yang kelebihan beban memiliki makna alami baik untuk pakar domain maupun ahli perangkat lunak. Jika kedua kelompok itu tidak sepakat tentang makna alami bagi operator, jangan berlebihan.
    • untuk tipe yang terlibat, tidak ada makna alami untuk operator dan konteks langsung (lebih disukai ekspresi yang sama, tetapi tidak lebih dari beberapa baris) selalu memperjelas apa arti operator. Contoh kategori ini adalah operator<<untuk stream.
Bart van Ingen Schenau
sumber
1
+1 dari saya, tapi argumen kedua juga bisa diterapkan pada warisan. Banyak orang tidak memiliki petunjuk tentang warisan dan mencoba menerapkannya pada segalanya. Saya pikir sebagian besar programmer akan setuju bahwa adalah mungkin untuk menyalahgunakan warisan. Apakah itu berarti warisan adalah "jahat" dan harus ditinggalkan dari bahasa pemrograman? Atau haruskah kita membiarkannya karena itu juga bisa berguna?
fredoverflow
@ FredOverflow Argumen kedua dapat diterapkan untuk apa pun yang "baru dan panas". Saya tidak memberikannya sebagai argumen untuk menghapus kelebihan operator dari suatu bahasa, tetapi sebagai alasan mengapa orang membantahnya. Sejauh yang saya ketahui, kelebihan operator berguna tetapi harus digunakan dengan hati-hati.
Bart van Ingen Schenau
IMHO, memungkinkan kelebihan &&dan ||dengan cara yang tidak menyiratkan pengurutan adalah kesalahan besar (IMHO, jika C ++ akan memungkinkan kelebihan itu, seharusnya menggunakan format "dua-fungsi" khusus, dengan fungsi pertama diperlukan untuk mengembalikan jenis yang secara implisit dapat dikonversi menjadi bilangan bulat, fungsi kedua dapat mengambil dua atau tiga argumen, dengan argumen "ekstra" dari fungsi kedua menjadi jenis pengembalian yang pertama. Kompiler akan memanggil fungsi pertama dan kemudian, jika kembali bukan nol, evaluasi operan kedua dan panggil fungsi kedua di atasnya.)
supercat
Tentu saja, itu tidak seaneh yang memungkinkan operator koma kelebihan beban. Kebetulan, satu hal kelebihan muatan yang saya tidak benar-benar lihat, tetapi ingin, akan menjadi sarana akses anggota yang mengikat ketat, memungkinkan ekspresi ingin foo.bar[3].Xditangani oleh fookelas, daripada mengharuskan foountuk mengekspos anggota yang dapat mendukung subskrip dan kemudian mengekspos anggota X. Jika seseorang ingin memaksakan evaluasi melalui akses anggota aktual, ia akan menulis ((foo.bar)[3]).X.
supercat
3

Berdasarkan pengalaman pribadi saya, cara Java memungkinkan beberapa metode, tetapi tidak kelebihan operator, berarti bahwa setiap kali Anda melihat operator, Anda tahu persis apa yang dilakukannya.

Anda tidak perlu melihat apakah *memanggil kode aneh tetapi tahu bahwa itu adalah multiply, dan berperilaku persis seperti cara yang didefinisikan oleh Spesifikasi Bahasa Jawa. Ini berarti Anda dapat berkonsentrasi pada perilaku aktual alih-alih mencari tahu semua hal gawang yang ditentukan oleh programmer.

Dengan kata lain, melarang kelebihan operator adalah manfaat bagi pembaca , bukan penulis , dan karenanya membuat program lebih mudah dikelola!


sumber
+1, dengan peringatan: C ++ memberi Anda cukup tali untuk menggantung diri. Tetapi jika saya ingin mengimplementasikan daftar tertaut dalam C ++, saya ingin kemampuan untuk menggunakan [] untuk mengakses elemen ke-n. Masuk akal untuk menggunakan operator untuk data yang (secara matematis berbicara) mereka valid.
Michael K
@Michael, Anda tidak bisa hidup dengan list.get(n)sintaks?
@ Thorbjørn: Ini sebenarnya baik-baik saja juga, mungkin contoh yang buruk. Waktu mungkin lebih baik - kelebihan +, - akan lebih masuk akal daripada time.add (anotherTime).
Michael K
4
@Michael: Tentang daftar tertaut, std::listtidak kelebihan operator[](atau memberikan cara pengindeksan lain ke dalam daftar), karena operasi seperti itu akan menjadi O (n), dan antarmuka daftar tidak boleh mengekspos fungsi seperti itu jika Anda peduli efisiensi. Klien mungkin tergoda untuk beralih pada daftar tertaut dengan indeks, membuat algoritma O (n) sia-sia O (n ^ 2). Anda melihat itu cukup sering dalam kode Java, terutama jika orang bekerja dengan Listantarmuka yang bertujuan untuk menghilangkan kompleksitas abstrak sepenuhnya.
fredoverflow
5
@Thor: "Tetapi untuk memastikan Anda harus memeriksa :)" ... Sekali lagi, ini tidak terkait dengan kelebihan operator . Jika Anda melihat time.add(anotherTime), Anda juga harus memeriksa apakah pemrogram perpustakaan menerapkan operasi add "dengan benar" (apa pun artinya).
fredoverflow
3

Satu perbedaan antara overloading a * bdan menelepon multiply(a,b)adalah bahwa yang terakhir dapat dengan mudah dipahami. Jika multiplyfungsi tersebut tidak kelebihan beban untuk jenis yang berbeda maka Anda dapat mengetahui dengan tepat apa fungsi yang akan dilakukan, tanpa harus melacak jenis adan b.

Linus Torvalds memiliki argumen yang menarik tentang kelebihan operator. Dalam sesuatu seperti pengembangan kernel linux, di mana sebagian besar perubahan dikirim melalui tambalan melalui email, penting bahwa pengelola dapat memahami apa yang akan dilakukan tambalan dengan hanya beberapa baris konteks di sekitar setiap perubahan. Jika fungsi dan operator tidak kelebihan beban maka tambalan dapat lebih mudah dibaca dalam konteks independen, karena Anda tidak harus melalui file yang diubah untuk mengetahui semua jenis dan memeriksa untuk operator kelebihan beban.

Scott Wales
sumber
Bukankah kernel linux dikembangkan dalam pure C? Mengapa membahas (operator) kelebihan beban sama sekali dalam konteks ini?
fredoverflow
Kekhawatirannya sama untuk setiap proyek dengan proses pengembangan yang serupa, terlepas dari bahasa. Overloading yang berlebihan dapat mempersulit untuk memahami dampak dari perubahan jika Anda harus melanjutkan beberapa baris dari file patch.
Scott Wales
@ FredOverflow: Kernel Linux benar-benar dalam GCC C. Ia menggunakan segala macam ekstensi yang memberikan C-nya hampir terasa C ++ pada beberapa waktu. Saya sedang memikirkan beberapa manipulasi tipe mewah.
Zan Lynx
2
@Scott: Tidak ada gunanya membahas "kejahatan" kelebihan beban sehubungan dengan proyek yang diprogram dalam C, karena C tidak memiliki kemampuan untuk membebani fungsi.
fredoverflow
3
Menurut saya Linus Torvalds memiliki sudut pandang yang sempit. Dia kadang-kadang mengkritik hal-hal yang tidak benar-benar berguna untuk pemrograman kernel Linux seolah-olah itu membuat mereka tidak cocok untuk penggunaan umum. Subversi adalah salah satu contohnya. Ini VCS yang bagus, tetapi pengembangan kernel Linux benar-benar membutuhkan VCS terdistribusi, jadi Linus mengkritik SVN secara umum.
David Thornley
2

Saya menduga itu ada hubungannya dengan melanggar harapan. Saya sudah terbiasa dengan C ++, Anda terbiasa dengan perilaku operator yang tidak didikte sepenuhnya oleh bahasa, dan Anda tidak akan terkejut ketika operator melakukan sesuatu yang aneh. Jika Anda terbiasa dengan bahasa yang tidak memiliki fitur itu, dan kemudian melihat kode C ++, Anda membawa harapan dari bahasa-bahasa lain, dan mungkin terkejut ketika Anda menemukan bahwa operator kelebihan beban melakukan sesuatu yang funky.

Secara pribadi saya pikir ada perbedaan. Saat Anda dapat mengubah perilaku sintaksis bawaan bahasa, itu menjadi lebih buram untuk dipikirkan. Bahasa yang tidak memungkinkan pemrograman meta secara sintaksis kurang kuat, tetapi secara konsep lebih mudah dipahami.

Joeri Sebrechts
sumber
Operator yang kelebihan beban tidak boleh melakukan "sesuatu yang aneh". Tidak apa-apa jika melakukan sesuatu yang kompleks, tentu saja. Tetapi hanya kelebihan ketika memiliki satu makna yang jelas.
Sjoerd
2

Saya pikir operator matematika yang kelebihan beban bukan masalah sebenarnya dengan operator yang kelebihan muatan di C ++. Saya pikir operator overload yang tidak boleh bergantung pada konteks ekspresi (yaitu tipe) adalah "jahat". Misalnya overloading , [ ] ( ) -> ->* new deleteatau bahkan unary *. Anda memiliki seperangkat harapan tertentu dari operator yang tidak boleh berubah.

Allon Guralnek
sumber
+1 Jangan membuat [] sama dengan ++.
Michael K
3
Apakah Anda mengatakan bahwa kami seharusnya tidak dapat membebani operator yang Anda sebutkan sama sekali ? Atau Anda hanya mengatakan bahwa kita harus membebani mereka hanya untuk tujuan waras? Karena saya akan benci melihat wadah tanpa operator[], tanpa fungsi operator(), petunjuk pintar tanpa operator->dan sebagainya.
fredoverflow
Saya mengatakan bahwa potensi masalah kelebihan operator dengan operasi matematika kecil dibandingkan dengan operator tersebut. Melakukan sesuatu yang pintar atau gila dengan operator matematika mungkin merepotkan, tetapi operator yang saya daftarkan, yang biasanya orang tidak anggap sebagai operator tetapi elemen bahasa dasar, harus selalu memenuhi harapan yang ditentukan oleh bahasa. []harus selalu berupa ->pengakses mirip array, dan harus selalu berarti mengakses anggota. Tidak masalah apakah itu sebenarnya array atau wadah yang berbeda, atau apakah itu pointer cerdas atau tidak.
Allon Guralnek
2

Saya sangat memahami Anda tidak suka argumen Joel tentang persembunyian. Aku juga tidak. Memang jauh lebih baik menggunakan '+' untuk hal-hal seperti tipe numerik bawaan atau untuk tipe Anda sendiri, misalnya, matriks. Saya akui ini rapi dan anggun untuk bisa melipatgandakan dua matriks dengan '*' alih-alih '.multiply ()'. Lagi pula, kami memiliki jenis abstraksi yang sama dalam kedua kasus tersebut.

Apa yang menyakitkan di sini adalah keterbacaan kode Anda. Dalam kasus kehidupan nyata, bukan dalam contoh akademis perkalian matriks. Terutama jika bahasa Anda memungkinkan untuk mendefinisikan operator yang awalnya tidak ada di inti bahasa, misalnya =:=. Banyak pertanyaan tambahan muncul pada saat ini. Tentang apa operator itu? Maksud saya apa yang diutamakan dari hal itu? Apa asosiatifnya? Di mana urutan yang a =:= b =:= cbenar - benar dieksekusi?

Itu sudah menjadi argumen terhadap overloading operator. Masih belum yakin? Memeriksa aturan diutamakan membawa Anda tidak lebih dari 10 detik? Ok, mari kita melangkah lebih jauh.

Jika Anda mulai menggunakan bahasa yang memungkinkan overloading operator, misalnya bahasa populer yang namanya dimulai dengan 'S', Anda akan dengan cepat mengetahui bahwa perancang perpustakaan suka mengganti operator. Tentu saja mereka berpendidikan tinggi, mereka mengikuti praktik terbaik (tidak ada sinisme di sini) dan semua API mereka masuk akal ketika kita melihatnya secara terpisah.

Sekarang bayangkan Anda harus menggunakan beberapa API yang banyak menggunakan operator kelebihan beban bersama dalam satu kode. Atau bahkan lebih baik - Anda harus membaca beberapa kode lama seperti itu. Inilah saat operator kelebihan muatan benar-benar menyebalkan. Pada dasarnya jika ada banyak operator kelebihan beban di satu tempat mereka akan segera mulai berbaur dengan karakter non-numerik lain dalam kode program Anda. Mereka akan berbaur dengan karakter non-alfanumerik yang bukan benar-benar operator tetapi lebih merupakan beberapa elemen tata bahasa bahasa yang lebih mendasar yang mendefinisikan hal-hal seperti blok dan cakupan, membentuk pernyataan kontrol aliran atau menunjukkan beberapa hal meta. Anda harus meletakkan kacamata dan memindahkan mata Anda 10 cm lebih dekat ke layar LCD untuk memahami kekacauan visual itu.

akosicki
sumber
1
Kelebihan operator yang ada dan menciptakan operator baru bukan hal yang sama, tetapi +1 dari saya.
fredoverflow
1

Secara umum, saya menghindari penggunaan operator yang berlebihan dengan cara yang tidak intuitif. Yaitu, jika saya memiliki kelas numerik, kelebihan * dapat diterima (dan dianjurkan). Namun, jika saya memiliki Karyawan kelas, apa yang akan dilakukan overloading *? Dengan kata lain, membebani operator dengan cara intuitif yang membuatnya mudah dibaca dan dipahami.

Diterima / Didorong:

class Complex
{
public:
    double r;
    double i;

    Complex operator*(const Compex& rhs)
    {
        Complex result;
        result.r = (r * rhs.r) - (i * rhs.i);
        result.i = (r * rhs.i) + (i * rhs.r);
        return result;
    }
};

Tidak dapat diterima:

class Employee
{
public:
    std::string name;
    std::string address;
    std::string phone_number;

    Employee operator* (const Employee& e)
    {
        // what the hell do I do here??
    }
};
Zac Howland
sumber
1
Melipatgandakan karyawan? Tentunya itu adalah pelanggaran berat, jika mereka melakukannya di meja ruang dewan, itu saja.
gbjbaanb
1

Selain apa yang telah dikatakan di sini, ada satu argumen lagi terhadap kelebihan operator. Memang, jika Anda menulis +, ini agak jelas bahwa Anda bermaksud menambahkan sesuatu pada sesuatu. Tapi ini tidak selalu terjadi.

C ++ itu sendiri memberikan contoh yang bagus dari kasus seperti itu. Bagaimana stream << 1seharusnya dibaca? aliran dialihkan ke kiri sebesar 1? Tidak jelas sama sekali kecuali Anda secara eksplisit tahu bahwa << di C ++ juga menulis ke aliran. Namun, jika operasi ini diimplementasikan sebagai metode, tidak ada pengembang waras yang akan menulis o.leftShift(1), itu akan menjadi seperti itu o.write(1).

Intinya adalah bahwa dengan membuat operator kelebihan tidak tersedia, bahasa membuat pemrogram memikirkan nama-nama operasi. Bahkan jika nama yang dipilih tidak sempurna, masih lebih sulit untuk salah mengartikan nama daripada tanda.

Malcolm
sumber
1

Dibandingkan dengan metode yang dijabarkan, operator lebih pendek, tetapi mereka juga tidak membutuhkan tanda kurung. Kurung relatif tidak nyaman untuk diketik. Dan Anda harus menyeimbangkannya. Secara total, panggilan metode apa pun membutuhkan tiga karakter derau biasa dibandingkan dengan operator. Ini membuat penggunaan operator sangat, sangat menggoda.
Kenapa lagi orang mau ini cout << "Hello world":?

Masalah dengan overloading adalah, bahwa kebanyakan programmer sangat malas dan kebanyakan programmer tidak mampu.

Apa yang mendorong pemrogram C ++ untuk penyalahgunaan operator kelebihan adalah bukan kehadirannya, tetapi tidak adanya cara yang lebih rapi untuk melakukan pemanggilan metode. Dan orang-orang tidak hanya takut kelebihan operator karena itu mungkin, tetapi karena itu dilakukan.
Perhatikan bahwa misalnya di Ruby dan Scala tidak ada yang takut kelebihan operator. Terlepas dari kenyataan, bahwa penggunaan operator tidak benar-benar lebih pendek dari metode, alasan lain adalah, bahwa Ruby membatasi kelebihan muatan operator ke minimum yang masuk akal, sementara Scala memungkinkan Anda untuk mendeklarasikan operator Anda sendiri sehingga menghindari tabrakan sepele.

back2dos
sumber
atau, dalam C #, untuk menggunakan + = untuk mengikat acara ke delegasi. Saya tidak berpikir bahwa menyalahkan fitur bahasa untuk kebodohan programmer adalah cara maju yang konstruktif.
gbjbaanb
0

Alasan Operator Overloading menakutkan, adalah karena ada sejumlah besar programmer yang tidak akan pernah BERPIKIR itu *tidak berarti hanya "mengalikan", sedangkan metode seperti foo.multiply(bar)setidaknya secara langsung menunjukkan kepada pemrogram itu bahwa seseorang menulis metode pengali kustom . Pada titik itu mereka akan bertanya-tanya mengapa dan pergi menyelidiki.

Saya telah bekerja dengan "programmer yang baik" yang berada di posisi tingkat tinggi yang akan menciptakan metode yang disebut "CompareValues" yang akan mengambil 2 argumen, dan menerapkan nilai dari satu ke yang lain dan mengembalikan boolean. Atau metode yang disebut "LoadTheValues" yang akan pergi ke database untuk 3 objek lain, mendapatkan nilai, melakukan perhitungan, memodifikasi thisdan menyimpannya ke database.

Jika saya bekerja dalam tim dengan tipe-tipe programmer seperti itu, saya langsung tahu untuk menyelidiki hal-hal yang telah mereka kerjakan. Jika mereka membebani operator secara berlebihan, saya sama sekali tidak tahu bahwa mereka melakukannya kecuali berasumsi mereka melakukannya dan mencari.

Dalam dunia yang sempurna, atau tim dengan programmer yang sempurna, kelebihan operator mungkin merupakan alat yang fantastis. Saya belum bekerja pada tim programmer yang sempurna, jadi itu sebabnya itu menakutkan.

James P. Wright
sumber