Mengapa Java tidak menawarkan kelebihan operator?

406

Datang dari C ++ ke Java, pertanyaan yang belum terjawab jelas adalah mengapa Java tidak termasuk operator overloading?

Bukankah Complex a, b, c; a = b + c;lebih sederhana dari itu Complex a, b, c; a = b.add(c);?

Adakah alasan yang diketahui untuk hal ini, argumen yang valid untuk tidak mengizinkan overloading operator? Apakah alasannya sewenang-wenang, atau hilang waktu?

rengolin
sumber
1
@zzzz, saya kesulitan membaca artikel itu. Apakah ini diterjemahkan secara otomatis, atau apakah bahasa Inggris adalah bahasa kedua penulis? Saya menemukan diskusi di sini jauh lebih bersih.
25
Bagi banyak orang yang menutup ini sebagai tidak konstruktif, pertanyaan ini telah menghasilkan beberapa dialog paling konstruktif yang pernah saya lihat di SO. Mungkin itu adalah kandidat yang lebih baik untuk programer.stackexchange.com , tetapi ada kalanya saya pikir SO terlalu meremehkan subjek yang lebih luas.
@NoNaMe mudah, hanya mental memasukkan sebuah dan para - artlcles hilang adalah giveaway mati bahwa orang tersebut baik bukan pembicara asli bahasa Inggris atau programmer (atau seperti orang ini, baik :) Programer alasan bisa drop artikel adalah bahwa hal itu dapat buat komentar lebih pendek dan pas di tempat yang disediakan .. dari sana, mereka terbiasa. Masalah saya adalah dengan tata letak, entah bagaimana saya selalu memukul situs itu di pencarian google. Untungnya ada ekstensi krom besar yang disebut Jelas bahwa format ulang sulit untuk membaca halaman luar biasa.
ycomp
1
Saya tidak melihat alasan mengapa & bagaimana OP menerima jawaban pertama? Jawaban yang ditulis oleh @ stackoverflow.com/users/14089/paercebal sangat bagus. Itu harus diterima.
Destructor

Jawaban:

13

Dengan asumsi Anda ingin menimpa nilai sebelumnya dari objek yang dirujuk oleh a, maka fungsi anggota harus dipanggil.

Complex a, b, c;
// ...
a = b.add(c);

Dalam C ++, ekspresi ini memberitahu kompiler untuk membuat tiga (3) objek pada stack, melakukan penambahan, dan menyalin nilai yang dihasilkan dari objek sementara ke objek yang ada a.

Namun, di Jawa, operator=tidak melakukan penyalinan nilai untuk tipe referensi, dan pengguna hanya bisa membuat tipe referensi baru, bukan tipe nilai. Jadi untuk jenis yang ditentukan pengguna bernama Complex, tugas berarti menyalin referensi ke nilai yang ada.

Pertimbangkan sebagai gantinya:

b.set(1, 0); // initialize to real number '1'
a = b; 
b.set(2, 0);
assert( !a.equals(b) ); // this assertion will fail

Dalam C ++, ini menyalin nilainya, sehingga perbandingannya akan menghasilkan tidak sama. Di Jawa, operator=melakukan salinan referensi, jadi adan bsekarang merujuk ke nilai yang sama. Akibatnya, perbandingan akan menghasilkan 'sama', karena objek akan dibandingkan dengan dirinya sendiri.

Perbedaan antara salinan dan referensi hanya menambah kebingungan operator yang berlebihan. Seperti yang disebutkan @Sebastian, Java dan C # keduanya harus berurusan dengan nilai dan kesetaraan referensi secara terpisah - operator+kemungkinan akan berurusan dengan nilai dan objek, tetapi operator=sudah diterapkan untuk menangani referensi.

Dalam C ++, Anda hanya harus berurusan dengan satu jenis perbandingan pada satu waktu, sehingga bisa kurang membingungkan. Misalnya, aktif Complex, operator=dan operator==keduanya bekerja pada nilai - nilai menyalin dan membandingkan nilai masing-masing.

Harun
sumber
6
Ini sangat sederhana, benar-benar ... Lakukan saja seperti Python dan tidak memiliki tugas kelebihan.
L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳
225
Jawaban ini sama sekali tidak menjawab pertanyaan. Anda hanya mengandalkan penggunaan tanda sama dengan java. Jika b + C mengembalikan Kompleks baru, maka a = b + c akan benar-benar valid, dan ya jauh lebih mudah dibaca. Bahkan jika Anda ingin memodifikasi a di tempat, a.set (b + c) adalah satu ton lebih mudah dibaca - terutama ketika aritmatika lebih dari sepele: a.set ((a + b c) / 5) atau a = a.multiply (b) .add (b.multiply (c)). bagi (5). Pilihan Anda ..
BT
24
Atau saya kira .. bukan pilihan Anda, seperti kasusnya
BT
9
Di C ++, Template Ekspresi menyelesaikan masalah salinan tambahan. Hampir semua perpustakaan aritmatika utama menggunakan teknik ini karena alasan ini. Juga, ini tidak menjawab pertanyaan, karena a = b + c hanyalah gula sintaksis untuk a.foo (b.bar (c)), yang sebenarnya merupakan pengamatan awal dalam pertanyaan.
Kaz Dragon
18
Ini bukan jawaban untuk pertanyaan yang diajukan. Ini adalah spekulasi seseorang tentang perbedaan tertentu antara Java dan C ++.
SChepurin
804

Ada banyak postingan yang mengeluhkan kelebihan operator.

Saya merasa saya harus mengklarifikasi konsep "operator overloading", menawarkan sudut pandang alternatif pada konsep ini.

Kode membingungkan?

Argumen ini salah.

Kebingungan dimungkinkan dalam semua bahasa ...

Sangat mudah untuk mengaburkan kode dalam C atau Java melalui fungsi / metode seperti di C ++ melalui overload operator:

// C++
T operator + (const T & a, const T & b) // add ?
{
   T c ;
   c.value = a.value - b.value ; // subtract !!!
   return c ;
}

// Java
static T add (T a, T b) // add ?
{
   T c = new T() ;
   c.value = a.value - b.value ; // subtract !!!
   return c ;
}

/* C */
T add (T a, T b) /* add ? */
{
   T c ;
   c.value = a.value - b.value ; /* subtract !!! */
   return c ;
}

... Bahkan di antarmuka standar Java

Sebagai contoh lain, mari kita lihat Cloneableantarmuka di Jawa:

Anda seharusnya mengkloning objek yang mengimplementasikan antarmuka ini. Tapi kamu bisa berbohong. Dan buat objek yang berbeda. Faktanya, antarmuka ini sangat lemah sehingga Anda bisa mengembalikan jenis objek lain secara bersamaan, hanya untuk bersenang-senang:

class MySincereHandShake implements Cloneable
{
    public Object clone()
    {
       return new MyVengefulKickInYourHead() ;
    }
}

Karena Cloneableantarmuka dapat disalahgunakan / dikaburkan, haruskah itu dilarang dengan alasan yang sama C ++ operator overload seharusnya?

Kita bisa membebani toString()metode suatu MyComplexNumberkelas untuk mengembalikannya pada jam yang ditentukan hari itu. Haruskah toString()kelebihan beban juga dilarang? Kita bisa menyabotase MyComplexNumber.equalsagar mengembalikan nilai acak, memodifikasi operan ... dll dll. Dll.

Di Jawa, seperti dalam C ++, atau bahasa apa pun, programmer harus menghormati semantik minimum saat menulis kode. Ini berarti menerapkan addfungsi yang menambah, dan Cloneablemetode implementasi yang mengkloning, dan ++operator daripada penambahan.

Apa sih yang membingungkan?

Sekarang kita tahu bahwa kode dapat disabotase bahkan melalui metode Java yang asli, kita dapat bertanya pada diri sendiri tentang penggunaan nyata dari operator yang berlebihan di C ++?

Notasi yang jelas dan alami: metode vs. kelebihan operator?

Kami akan membandingkan di bawah ini, untuk kasus yang berbeda, kode "sama" di Java dan C ++, untuk memiliki gagasan tentang jenis gaya pengkodean yang lebih jelas.

Perbandingan alami:

// C++ comparison for built-ins and user-defined types
bool    isEqual          = A == B ;
bool    isNotEqual       = A != B ;
bool    isLesser         = A <  B ;
bool    isLesserOrEqual  = A <= B ;

// Java comparison for user-defined types
boolean isEqual          = A.equals(B) ;
boolean isNotEqual       = ! A.equals(B) ;
boolean isLesser         = A.comparesTo(B) < 0 ;
boolean isLesserOrEqual  = A.comparesTo(B) <= 0 ;

Harap dicatat bahwa A dan B dapat berupa jenis apa pun dalam C ++, selama operator kelebihan beban disediakan. Di Jawa, ketika A dan B bukan primitif, kode dapat menjadi sangat membingungkan, bahkan untuk objek seperti primitif (BigInteger, dll.) ...

Pengakses dan larik array / wadah alami:

// C++ container accessors, more natural
value        = myArray[25] ;         // subscript operator
value        = myVector[25] ;        // subscript operator
value        = myString[25] ;        // subscript operator
value        = myMap["25"] ;         // subscript operator
myArray[25]  = value ;               // subscript operator
myVector[25] = value ;               // subscript operator
myString[25] = value ;               // subscript operator
myMap["25"]  = value ;               // subscript operator

// Java container accessors, each one has its special notation
value        = myArray[25] ;         // subscript operator
value        = myVector.get(25) ;    // method get
value        = myString.charAt(25) ; // method charAt
value        = myMap.get("25") ;     // method get
myArray[25]  = value ;               // subscript operator
myVector.set(25, value) ;            // method set
myMap.put("25", value) ;             // method put

Di Jawa, kami melihat bahwa untuk setiap wadah melakukan hal yang sama (mengakses kontennya melalui indeks atau pengidentifikasi), kami memiliki cara berbeda untuk melakukannya, yang membingungkan.

Di C ++, setiap kontainer menggunakan cara yang sama untuk mengakses kontennya, terima kasih kepada operator yang berlebihan.

Manipulasi tipe lanjutan alami

Contoh di bawah ini menggunakan Matrixobjek, ditemukan menggunakan tautan pertama yang ditemukan di Google untuk "objek Java Matrix " dan "objek C ++ Matrix ":

// C++ YMatrix matrix implementation on CodeProject
// http://www.codeproject.com/KB/architecture/ymatrix.aspx
// A, B, C, D, E, F are Matrix objects;
E =  A * (B / 2) ;
E += (A - B) * (C + D) ;
F =  E ;                  // deep copy of the matrix

// Java JAMA matrix implementation (seriously...)
// http://math.nist.gov/javanumerics/jama/doc/
// A, B, C, D, E, F are Matrix objects;
E = A.times(B.times(0.5)) ;
E.plusEquals(A.minus(B).times(C.plus(D))) ;
F = E.copy() ;            // deep copy of the matrix

Dan ini tidak terbatas pada matriks. The BigIntegerdan BigDecimalkelas Java menderita bertele-tele membingungkan yang sama, sedangkan setara dalam C ++ adalah sebagai jelas seperti built-in jenis.

Iterator alami:

// C++ Random Access iterators
++it ;                  // move to the next item
--it ;                  // move to the previous item
it += 5 ;               // move to the next 5th item (random access)
value = *it ;           // gets the value of the current item
*it = 3.1415 ;          // sets the value 3.1415 to the current item
(*it).foo() ;           // call method foo() of the current item

// Java ListIterator<E> "bi-directional" iterators
value = it.next() ;     // move to the next item & return the value
value = it.previous() ; // move to the previous item & return the value
it.set(3.1415) ;        // sets the value 3.1415 to the current item

Functors alami:

// C++ Functors
myFunctorObject("Hello World", 42) ;

// Java Functors ???
myFunctorObject.execute("Hello World", 42) ;

Rangkaian teks:

// C++ stream handling (with the << operator)
                    stringStream   << "Hello " << 25 << " World" ;
                    fileStream     << "Hello " << 25 << " World" ;
                    outputStream   << "Hello " << 25 << " World" ;
                    networkStream  << "Hello " << 25 << " World" ;
anythingThatOverloadsShiftOperator << "Hello " << 25 << " World" ;

// Java concatenation
myStringBuffer.append("Hello ").append(25).append(" World") ;

Ok, di Jawa Anda bisa menggunakan MyString = "Hello " + 25 + " World" ;juga ... Tapi, tunggu sebentar: Ini overloading operator, bukan? Bukankah itu curang ???

:-D

Kode generik?

Operan pemodifikasi kode generik yang sama harus dapat digunakan baik untuk built-in / primitif (yang tidak memiliki antarmuka di Jawa), objek standar (yang tidak dapat memiliki antarmuka yang tepat), dan objek yang ditentukan pengguna.

Misalnya, menghitung nilai rata-rata dari dua nilai tipe arbitrer:

// C++ primitive/advanced types
template<typename T>
T getAverage(const T & p_lhs, const T & p_rhs)
{
   return (p_lhs + p_rhs) / 2 ;
}

int     intValue     = getAverage(25, 42) ;
double  doubleValue  = getAverage(25.25, 42.42) ;
complex complexValue = getAverage(cA, cB) ; // cA, cB are complex
Matrix  matrixValue  = getAverage(mA, mB) ; // mA, mB are Matrix

// Java primitive/advanced types
// It won't really work in Java, even with generics. Sorry.

Membahas kelebihan operator

Sekarang kita telah melihat perbandingan yang adil antara kode C ++ menggunakan operator overloading, dan kode yang sama di Jawa, kita sekarang dapat membahas "operator overloading" sebagai sebuah konsep.

Kelebihan operator sudah ada sejak sebelum komputer

Bahkan di luar ilmu komputer, ada operator overloading: Misalnya, dalam matematika, operator seperti +, -, *, dll kelebihan beban.

Memang, signifikansi +, -, *, dll perubahan tergantung pada jenis dari operan (numeric, vektor, fungsi gelombang kuantum, matriks, dll).

Sebagian besar dari kita, sebagai bagian dari program sains kami, belajar banyak signifikansi untuk operator, tergantung pada jenis operan. Apakah kita mendapati mereka membingungkan, mereka?

Kelebihan operator tergantung pada operannya

Ini adalah bagian terpenting dari kelebihan operator: Seperti dalam matematika, atau dalam fisika, operasi tergantung pada jenis operannya.

Jadi, ketahuilah jenis operan, dan Anda akan tahu efek operasinya.

Bahkan C dan Java memiliki operator (hard-code) overloading

Dalam C, perilaku nyata dari operator akan berubah sesuai dengan operannya. Misalnya, menambahkan dua bilangan bulat berbeda dari menambahkan dua ganda, atau bahkan satu bilangan bulat dan satu ganda. Bahkan ada domain aritmatika pointer keseluruhan (tanpa casting, Anda dapat menambahkan pointer ke integer, tetapi Anda tidak dapat menambahkan dua pointer ...).

Di Jawa, tidak ada pointer aritmatika, tetapi seseorang masih menemukan rangkaian string tanpa +operator akan cukup konyol untuk membenarkan pengecualian dalam kredo "operator kelebihan muatan jahat".

Hanya saja Anda, sebagai kode C (karena alasan historis) atau Java (karena alasan pribadi , lihat di bawah), Anda tidak dapat menyediakan kode Anda sendiri.

Di C ++, kelebihan operator bukan opsional ...

Dalam C ++, overloading operator untuk tipe bawaan tidak dimungkinkan (dan ini adalah hal yang baik), tetapi tipe yang ditentukan pengguna dapat memiliki overload operator yang ditentukan pengguna .

Seperti yang sudah dikatakan sebelumnya, dalam C ++, dan sebaliknya ke Java, tipe pengguna tidak dianggap sebagai warga kelas dua bahasa, jika dibandingkan dengan tipe bawaan. Jadi, jika tipe bawaan memiliki operator, tipe pengguna harus dapat memilikinya juga.

Yang benar adalah bahwa, seperti toString(), clone(), equals()metode adalah untuk Java ( yaitu kuasi-standar-seperti ), C ++ operator overloading begitu banyak bagian dari C ++ sehingga menjadi sebagai alam sebagai operator C yang asli, atau sebelum metode Java disebutkan.

Dikombinasikan dengan pemrograman template, overloading operator menjadi pola desain yang terkenal. Faktanya, Anda tidak bisa melangkah terlalu jauh di STL tanpa menggunakan operator yang kelebihan beban, dan operator yang kelebihan beban untuk kelas Anda sendiri.

... tapi jangan disalahgunakan

Overloading operator harus berusaha untuk menghormati semantik operator. Jangan kurangi dalam +operator (seperti dalam "jangan kurangi dalam suatu addfungsi", atau "kembalikan omong kosong dalam suatu clonemetode").

Kelebihan beban pemain bisa sangat berbahaya karena dapat menyebabkan ambiguitas. Jadi mereka harus benar-benar dicadangkan untuk kasus-kasus yang terdefinisi dengan baik. Adapun &&dan ||, tidak pernah membebani mereka kecuali jika Anda benar-benar tahu apa yang Anda lakukan, karena Anda akan kehilangan evaluasi hubung singkat bahwa operator asli &&dan ||menikmati.

Jadi ... Ok ... Lalu mengapa tidak mungkin di Jawa?

Karena James Gosling berkata demikian:

Saya membiarkan operator kelebihan beban sebagai pilihan yang cukup pribadi karena saya telah melihat terlalu banyak orang menyalahgunakannya di C ++.

James Gosling. Sumber: http://www.gotw.ca/publications/c_family_interview.htm

Silakan bandingkan teks Gosling di atas dengan Stroustrup di bawah ini:

Banyak keputusan desain C ++ berakar pada ketidaksukaan saya karena memaksa orang untuk melakukan sesuatu dengan cara tertentu [...] Sering kali, saya tergoda untuk melarang fitur yang saya pribadi tidak suka, saya menahan diri untuk tidak melakukannya karena saya tidak berpikir saya punya hak untuk memaksakan pandangan saya pada orang lain .

Bjarne Stroustrup. Sumber: Desain dan Evolusi C ++ (1.3 Latar Belakang Umum)

Apakah kelebihan beban operator menguntungkan Java?

Beberapa objek akan sangat diuntungkan dari kelebihan operator (jenis beton atau numerik, seperti BigDecimal, bilangan kompleks, matriks, wadah, iterator, pembanding, pengurai, dll.).

Dalam C ++, Anda bisa mendapat untung dari manfaat ini karena kerendahan hati Stroustrup. Di Jawa, Anda benar-benar kacau karena pilihan pribadi Gosling .

Bisakah itu ditambahkan ke Jawa?

Alasan untuk tidak menambah kelebihan operator sekarang di Jawa bisa menjadi perpaduan politik internal, alergi terhadap fitur, ketidakpercayaan pengembang (Anda tahu, penyabot yang tampaknya menghantui tim Java ...), kompatibilitas dengan JVM sebelumnya, waktu untuk menulis spesifikasi yang benar, dll.

Jadi jangan menahan nafas menunggu fitur ini ...

Tetapi mereka melakukannya dalam C # !!!

Ya...

Meskipun ini bukan satu-satunya perbedaan antara kedua bahasa, yang satu ini tidak pernah gagal untuk menghibur saya.

Rupanya, orang-orang C #, dengan "setiap primitif adalah a struct, dan structberasal dari Object" , melakukannya dengan benar pada percobaan pertama.

Dan mereka melakukannya dalam bahasa lain !!!

Terlepas dari semua FUD terhadap kelebihan operator yang didefinisikan, bahasa berikut mendukungnya: Scala , Dart , Python , F # , C # , D , Algol 68 , Smalltalk , Groovy , Perl 6 , C ++, Ruby , Haskell , MATLAB , Eiffel , Lua , Clojure , Fortran 90 , Swift , Ada , Delphi 2005 ...

Begitu banyak bahasa, dengan begitu banyak filsafat yang berbeda (dan terkadang bertentangan), namun mereka semua sepakat tentang hal itu.

Bahan untuk dipikirkan...

paercebal
sumber
50
Ini jawaban yang sangat bagus. Saya tidak setuju dengan itu, tetapi itu masih merupakan jawaban yang sangat baik. Saya pikir masalah yang mungkin terjadi dengan kelebihan yang buruk melebihi nilai kelebihan yang baik.
Douglas Leeder
69
@Douglas Leeder: Terima kasih! Kelebihan operator seperti OOP. Pertama kali Anda belajar melakukannya, Anda menulis kelebihan di mana-mana karena Anda akan meletakkan kelas dasar dan warisan di mana-mana (seperti, ironi manis, Java API). Tapi ini berlalu cukup cepat dan kemudian Anda menghargai kemungkinan sambil tidak menyalahgunakannya. Pengalaman 10-tahun + saya sendiri tentang C ++ adalah bahwa jumlah kelebihan beban buruk yang saya lihat baik dalam kode saya dan kode dari coders lain sangat rendah saya percaya saya bisa menghitungnya di satu sisi. Dan ini jauh lebih sedikit daripada jumlah keseluruhan bug dengan sprintf, strcat, memset, dan buffer overruns.
paercebal
11
@Douglas Leeder: Saya percaya, setelah membahas tentang hal itu dalam pertanyaan SO lainnya, bahwa kesenjangan antara "kekasih" dan "pembenci" kelebihan operator mungkin disebabkan oleh perbedaan dalam pendekatan mereka terhadap kode: "Pembenci" lebih "berfungsi yang penting ", artinya mereka mengharapkan fungsi untuk melakukan satu hal, dan satu hal saja. Dengan demikian operator harus bekerja seperti yang dirancang oleh bahasa. "Pecinta" lebih tentang "objek harus berperilaku", yang berarti bahwa mereka menerima lebih mudah bahwa fungsi (dan dengan demikian, operator) dapat mengubah perilaku mereka sesuai dengan jenis parameternya.
paercebal
103
Jawaban epik. Salah satu sanggahan paling berkualitas yang pernah saya baca.
Sebastian Mach
7
@MaartenBodewes: Semua contoh yang saya tulis di atas, dan semua yang mengganggu Anda adalah "sebagai pengembang, Anda kacau karena pilihan pribadi Gosling" ? Tolong, tulis jawaban Anda sendiri, membela sudut pandang "Anda pengembang bodoh, biarkan orang jenius memutuskan untuk Anda apa yang Anda butuhkan" . Diskusi ini tidak memiliki tujuan.
paercebal
44

James Gosling disamakan merancang Java sebagai berikut:

"Ada prinsip tentang pindah, ketika kamu pindah dari satu apartemen ke apartemen lain. Eksperimen yang menarik adalah mengemas apartemenmu dan memasukkan semuanya ke dalam kotak, lalu pindah ke apartemen berikutnya dan tidak membongkar apa pun sampai kamu membutuhkannya. Jadi, kamu sedang membuat makanan pertama Anda, dan Anda mengeluarkan sesuatu dari kotak. Kemudian setelah sebulan atau lebih Anda telah menggunakannya untuk mengetahui apa saja hal-hal dalam hidup Anda yang sebenarnya Anda butuhkan, dan kemudian Anda mengambil sisa dari hal-hal - lupakan betapa Anda menyukainya atau betapa kerennya itu - dan Anda hanya membuangnya Sungguh menakjubkan bagaimana hal itu menyederhanakan hidup Anda, dan Anda dapat menggunakan prinsip itu dalam semua jenis masalah desain: tidak melakukan sesuatu hanya karena mereka Keren atau hanya karena mereka menarik. "

Anda dapat membaca konteks kutipan di sini

Pada dasarnya kelebihan operator sangat bagus untuk kelas yang memodelkan semacam titik, mata uang, atau angka kompleks. Tetapi setelah itu Anda mulai kehabisan contoh dengan cepat.

Faktor lain adalah penyalahgunaan fitur dalam C ++ oleh pengembang yang membebani operator seperti '&&', '||', operator pemain, dan tentu saja 'baru'. Kompleksitas yang dihasilkan dari menggabungkan ini dengan nilai by pass dan pengecualian tercakup dengan baik dalam C ++ Luar Biasa .

Garth Gilmour
sumber
6
Bisakah Anda memberikan contoh kode "kompleksitas overloading operator dikombinasikan dengan pass-by-value dan pengecualian"? Meskipun beberapa tahun bermain dengan bahasa tersebut, dan memiliki dan telah membaca semua buku yang efektif / luar biasa tentang C ++, saya gagal memahami apa yang Anda maksud dengan itu.
paercebal
60
Apa yang berhasil untuk James Gosling tidak akan bekerja untuk semua orang. Dia sangat picik karena mengekstrapolasi eksperimen pengemasannya yang "menarik" berarti "Membuang segala yang ada di dunia yang tidak aku butuhkan, jadi tidak ada yang bisa menggunakan barang itu." Dia jelas tidak tahu apa yang saya butuhkan atau gunakan.
BT
49
@BT: Kebanyakan enlightning adalah sudut pandang Gosling bila dibandingkan dengan sudut pandang Stroustrup tentang masalah ini: Many C++ design decisions have their roots in my dislike for forcing people to do things in some particular way [...] Often, I was tempted to outlaw a feature I personally disliked, I refrained from doing so because I did not think I had the right to force my views on others. (B. Stroustrup).
paercebal
29
@Software Monkey: "C ++, banyak dicerca vs yang lain, Java, sangat disukai" Ini adalah sensasi pemasaran. Ingat bahwa C ++ tumbuh sendiri, sedangkan Java (dan .NET) mendapat untung dari buldoser pemasaran. Bukankah aneh bahwa untuk "bahasa yang disukai banyak orang", Java terbatas pada aplikasi server, sedangkan "banyak dicerca" (mungkin oleh pengembang dan manajer Java yang ingin menurunkan biaya produksi kode) C ++ berubah dari sangat tinggi- server kinerja ke game berkinerja tinggi? [...]
paercebal
16
@Hassan: Setiap bahasa memiliki retasannya, generik Java menjadi salah satu contoh yang bagus. Sekarang, tentang I'd like them to go have a look at some C++ code out there that is hideously put together with weird hacks and "exceptional" features of the language: Pemrogram yang buruk akan menulis kode yang buruk apa pun bahasanya. Hanya mencoba untuk meniru "pass-by-reference" untuk parameter fungsi di Jawa untuk memiliki ide. Saya telah melihat kode, dan tertawa sangat keras sampai sakit. Ini adalah jenis hal yang tidak digunakan Gosling, oleh karena itu, diperlukan peretasan yang mengerikan di Jawa, namun, ada secara asli, dengan biaya nol, baik di C # dan C ++.
paercebal
22

Lihat Boost.Units: tautan teks

Ini memberikan analisis Dimensi nol-overhead melalui overloading operator. Seberapa jelas ini bisa didapat?

quantity<force>     F = 2.0*newton;
quantity<length>    dx = 2.0*meter;
quantity<energy>    E = F * dx;
std::cout << "Energy = " << E << endl;

akan benar-benar menampilkan "Energi = 4 J" yang benar.

pengguna15793
sumber
1
"Bagaimana tepatnya jika mempersulit pemeliharaan dan di mana kode yang membingungkan ini?"
Mooing Duck
13

Perancang Java memutuskan bahwa overloading operator lebih merepotkan daripada nilainya. Sederhana seperti itu.

Dalam bahasa di mana setiap variabel objek sebenarnya referensi, operator overloading mendapat bahaya tambahan menjadi sangat tidak logis - setidaknya untuk programmer C ++. Bandingkan situasi dengan operator C # == yang kelebihan beban dan Object.Equalsdan Object.ReferenceEquals(atau apa pun namanya).

Sebastian Redl
sumber
8

Groovy memiliki operator kelebihan beban, dan berjalan di JVM. Jika Anda tidak keberatan hit kinerja (yang semakin kecil setiap hari). Otomatis berdasarkan nama metode. misalnya, '+' memanggil metode 'plus (argumen)'.

Nuh
sumber
4
Saya berharap semua bahasa sintaksis dengan overloading operator akan menggunakan teknik itu. Saya tidak pernah mengerti mengapa mereka harus menciptakan versi khusus penamaan dan pencarian metode. Stroustrup tidak menyebutkan alternatif dalam D & EC ++. Tim C # mengambil pendekatan yang tepat dengan sintaks Linq ( where ...menjadi .Where(i => ... ). Kalau saja mereka melakukan hal yang sama dengan operator aritmatika, banyak hal akan lebih sederhana dan lebih kuat. Java memiliki keuntungan dari batu tulis yang bersih dan bisa mendapatkan ini dengan benar (meskipun untuk alasan keagamaan, mungkin tidak akan pernah).
Daniel Earwicker
@DanielEarwicker, saya sering mencatat bahwa ketika ada perselisihan yang rumit bahwa orang-orang akan menandai motivasi untuk kedua pihak sebagai sifat "religius".
@ ya, saya bisa hidup dengan subset terbatas operator kelebihan seperti ini, asalkan ada tag khusus untuk nama-nama metode yang membuat mereka berbeda secara visual. Sesuatu seperti mendefinisikan metode __plus () untuk implementasi OL "+", dan tinggal terlalu jauh dengan hal-hal yang berlebihan seperti cast dan bahkan array subscript. Yang tidak ingin saya jalani adalah cara C ++ dan C # merasa cocok untuk mengimplementasikannya.
2
Bukan jawaban. Ada banyak bahasa yang berjalan di VM. Overloading operator seharusnya bukan alasan yang baik untuk beralih bahasa.
Maarten Bodewes
6

Saya pikir ini mungkin merupakan pilihan desain sadar untuk memaksa pengembang untuk membuat fungsi yang namanya dengan jelas mengomunikasikan niat mereka. Dalam C ++ pengembang akan membebani operator dengan fungsionalitas yang sering kali tidak memiliki hubungan dengan sifat yang diterima secara umum dari operator yang diberikan, sehingga hampir tidak mungkin untuk menentukan apa yang dilakukan sepotong kode tanpa melihat definisi operator.

pengguna14128
sumber
14
In C++ developers would overload operators with functionality that would often have no relation to the commonly accepted nature of the given operator: Ini adalah pernyataan serampangan. Saya seorang pengembang C ++ yang profesional sejak 12 tahun, dan saya jarang mengalami masalah ini. Bahkan, sebagian besar bug dan kesalahan desain yang saya lihat di C ++ ada dalam kode C-style ( void *, gips, dll.)
paercebal
6
-1. Setiap variabel yang Anda tetapkan adalah simbol, sama seperti simbol operator aritmatika. Apakah Anda menggunakan frasa untuk memberi nama variabel itu, satu kata, atau satu huruf, adalah keputusan Anda (atau tim Anda). Siapa yang mengatakan apa yang bermakna dan apa yang tidak? Jawabannya adalah Anda, sang programmer. Dalam matematika murni, perkalian antara matriks berarti sesuatu yang berbeda dengan perkalian antara dua angka dalam aritmatika dasar. Namun kami menggunakan simbol yang sama untuk kedua jenis penggandaan.
Insinyur
2
pa al erc pa pa pa unfortunately: Pernyataannya sayangnya benar. Anda harus melihat tidak lebih jauh dari IOstreams untuk melihatnya dalam tindakan. Untungnya sebagian besar pengembang lebih berhati-hati dalam menemukan semantik baru untuk operator yang ada.
Ben Voigt
5
@BenVoigt: [...] Dan saya bahkan tidak menyebutkan fakta bahwa addfungsi tersebut dapat benar-benar disalahgunakan (seperti melakukan penggandaan, atau mendapatkan mutex) ... Penyalahgunaan yang disebutkan oleh user14128 tidak terbatas pada operator, tetapi ada semacam ketakutan patologis tentang kelebihan operator yang saya yakini berasal dari masa-masa awal C vs C ++, rasa takut yang tidak termodifikasi langsung ke Jawa, tapi untungnya, tidak masuk ke C # ... Pada akhirnya, menghormati semantik yang menghormati dan menulis fungsi / operator yang jelas adalah pekerjaan pengembang. Bukan bahasa.
paercebal
3
@ jbo5112: Contoh: cout << f() || g(); kurung tidak membuatnya lebih jelas, mereka membuatnya benar. Dan jika operator bit shift tidak disalahgunakan, mereka tidak akan diperlukan. Kenapa cout << (5&3) << endl;lebih baik dari itu cout.fmt(5&3)(endl);? Menggunakan operator fungsi panggilan pada variabel anggota functor akan menjadi desain yang jauh lebih baik untuk stream daripada repurposing operator bitwise hanya karena mesin terbang terlihat bagus. Tapi ini jauh dari satu-satunya yang salah dengan aliran.
Ben Voigt
5

Nah, Anda dapat benar-benar menembak diri sendiri dengan operator yang kelebihan beban. Ini seperti dengan pointer orang membuat kesalahan bodoh dengan mereka dan jadi diputuskan untuk mengambil gunting.

Setidaknya saya pikir itulah alasannya. Aku tetap di sisimu. :)

Sarien
sumber
Seperti misalnya kesalahan bodoh ini ...
Amir Kirsh
2
Itu cara berpikir yang sangat buruk. Anda dapat menembak diri sendiri di kaki, kami lebih baik memotong tangan Anda, sehingga Anda tidak akan bisa melakukannya. Dan tentu saja kami mengira bahwa Anda adalah seorang idiot yang akan menembak dirinya sendiri.
ntj
5

Beberapa orang mengatakan bahwa overloading operator di Jawa akan menyebabkan obsfuscation. Pernahkah orang-orang itu berhenti untuk melihat beberapa kode Java melakukan beberapa matematika dasar seperti meningkatkan nilai keuangan dengan persentase menggunakan BigDecimal? .... verbositas dari latihan semacam itu menjadi demonstrasi sendiri dari obsfuscation. Ironisnya, menambahkan overloading operator ke Jawa akan memungkinkan kami untuk membuat kelas Mata Uang kami sendiri yang akan membuat kode matematika seperti itu elegan dan sederhana (kurang usang).

Volksman
sumber
4

Mengatakan bahwa operator kelebihan muatan mengarah ke kesalahan ketik logis dari operator yang tidak cocok dengan logika operasi, itu seperti mengatakan apa-apa. Jenis kesalahan yang sama akan terjadi jika nama fungsi tidak sesuai untuk logika operasi - jadi apa solusinya: jatuhkan kemampuan penggunaan fungsi !? Ini adalah jawaban yang lucu - "Tidak pantas untuk logika operasi", setiap nama parameter, setiap kelas, fungsi atau apa pun yang secara logika tidak pantas. Saya berpikir bahwa opsi ini harus tersedia dalam bahasa pemrograman yang terhormat, dan orang-orang yang berpikir itu tidak aman - hei, tidak ada yang bilang Anda harus menggunakannya. Mari kita ambil C #. Mereka menjatuhkan pointer tetapi hei - ada pernyataan 'kode tidak aman' - program yang Anda inginkan dengan risiko Anda sendiri.

Kvant
sumber
4

Secara teknis, ada kelebihan operator di setiap bahasa pemrograman yang dapat menangani berbagai jenis angka, misalnya bilangan bulat dan bilangan real. Penjelasan: Istilah overloading berarti hanya ada beberapa implementasi untuk satu fungsi. Dalam sebagian besar bahasa pemrograman, implementasi yang berbeda disediakan untuk operator +, satu untuk bilangan bulat, satu untuk real, ini disebut operator overloading.

Sekarang, banyak orang merasa aneh bahwa Java memiliki operator kelebihan untuk operator + untuk menambahkan string bersama-sama, dan dari sudut pandang matematika ini memang aneh, tetapi dilihat dari sudut pandang pengembang bahasa pemrograman, tidak ada yang salah dengan menambahkan kelebihan operator bawaan untuk operator + untuk kelas lain mis. String. Namun, sebagian besar orang setuju bahwa sekali Anda menambahkan overin bawaan untuk + untuk String, maka umumnya merupakan ide bagus untuk menyediakan fungsionalitas ini untuk pengembang juga.

Sepenuhnya tidak setuju dengan kekeliruan yang berlebihan dari operator mengaburkan kode, karena hal ini dibiarkan oleh pengembang untuk memutuskan. Ini naif untuk berpikir, dan sejujurnya, sudah semakin tua.

+1 untuk menambahkan overloading operator di Java 8.

Olai
sumber
Penggunaan Java +untuk menggabungkan string-ish apa pun adalah IMHO cukup mengerikan, seperti kelebihan beban /dalam C dan FORTRAN untuk pembagian keseluruhan dan fraksional. Dalam banyak versi Pascal, penggunaan operator aritmatika pada jenis numerik apa pun akan menghasilkan hasil yang setara secara numerik dengan casting operan Real, meskipun hasil yang mungkin bukan bilangan bulat harus dimasukkan melalui Truncatau Roundsebelum mereka dapat ditugaskan ke bilangan bulat.
supercat
2

Dengan asumsi Java sebagai bahasa implementasi maka a, b, dan c semuanya akan menjadi referensi untuk mengetik Complex dengan nilai awal nol. Juga dengan anggapan bahwa Kompleks tidak dapat diubah sebagai BigInteger yang disebutkan dan BigDecimal abadi yang serupa , saya pikir saya maksudkan yang berikut, karena Anda menetapkan referensi ke Kompleks yang dikembalikan dari menambahkan b dan c, dan tidak membandingkan referensi ini dengan a.

Bukan:

Complex a, b, c; a = b + c;

jauh lebih sederhana dari:

Complex a, b, c; a = b.add(c);
David Schlosnagle
sumber
2
Apakah saya ;) Persamaan dapat berarti penugasan atau perbandingan, tetapi = selalu penugasan dan == selalu perbandingan. Nama dapat memperkenalkan sumber kesalahan besar sendiri.
1

Terkadang akan menyenangkan untuk memiliki kelebihan operator, kelas teman dan banyak warisan.

Namun saya masih berpikir itu adalah keputusan yang bagus. Jika Java memiliki operator overloading maka kita tidak pernah bisa memastikan makna operator tanpa melihat melalui kode sumber. Saat ini itu tidak perlu. Dan saya pikir contoh Anda menggunakan metode bukan overloading operator juga cukup mudah dibaca. Jika Anda ingin memperjelas hal-hal Anda selalu dapat menambahkan komentar di atas pernyataan berbulu.

// a = b + c
Complex a, b, c; a = b.add(c);

sumber
12
Tentu saja, seperti yang disebutkan di tempat lain Anda tidak pernah bisa yakin tentang arti dari fungsi add.
Eclipse
Benar, saya masih merasa terhibur mengetahui bahwa setidaknya operator saya memiliki kode yang sulit. Tentu saja, memiliki fitur dan menggunakannya dengan bijaksana hanya akan membantu kita. Masalahnya adalah sulit untuk mengetahui apakah seseorang telah menggunakannya dengan bijaksana. Dan Anda setuju dengan definisi yang masuk akal. :-)
1
Komentar yang ditambahkan untuk memperjelas kode, akan seperti apa kode itu dalam bahasa yang mendukung operator kelebihan muatan. Lebih jauh, fakta bahwa komentar tersebut ditulis dalam istilah operator memungkiri oposisi Anda terhadap kelebihan operator.
Aluan Haddad
0

Ini bukan alasan yang baik untuk melarangnya, tetapi alasan praktis:

Orang tidak selalu menggunakannya secara bertanggung jawab. Lihat contoh ini dari scapy library Python:

>>> IP()
<IP |>
>>> IP()/TCP()
<IP frag=0 proto=TCP |<TCP |>>
>>> Ether()/IP()/TCP()
<Ether type=0x800 |<IP frag=0 proto=TCP |<TCP |>>>
>>> IP()/TCP()/"GET / HTTP/1.0\r\n\r\n"
<IP frag=0 proto=TCP |<TCP |<Raw load='GET / HTTP/1.0\r\n\r\n' |>>>
>>> Ether()/IP()/IP()/UDP()
<Ether type=0x800 |<IP frag=0 proto=IP |<IP frag=0 proto=UDP |<UDP |>>>>
>>> IP(proto=55)/TCP()
<IP frag=0 proto=55 |<TCP |>>

Berikut penjelasannya:

Operator / telah digunakan sebagai operator komposisi antara dua lapisan. Ketika melakukannya, lapisan bawah dapat memiliki satu atau lebih bidang standarnya kelebihan beban sesuai dengan lapisan atas. (Anda masih bisa memberikan nilai yang Anda inginkan). Tali dapat digunakan sebagai lapisan mentah.

Sarien
sumber
0

Alternatif untuk Dukungan Asli Java Overloading Operator

Karena Java tidak memiliki kelebihan operator, berikut adalah beberapa alternatif yang dapat Anda perhatikan:

  1. Gunakan bahasa lain. Baik Groovy dan Scala memiliki kelebihan operator, dan berbasis di Jawa.
  2. Gunakan java-oo , sebuah plugin yang memungkinkan operator kelebihan beban di Jawa. Perhatikan bahwa BUKAN platform independen. Juga, ia memiliki banyak masalah, dan tidak kompatibel dengan rilis terbaru Java (yaitu Java 10). ( Sumber StackOverflow Asli )
  3. Gunakan JNI , Java Native Interface, atau alternatif. Ini memungkinkan Anda untuk menulis metode C atau C ++ (mungkin yang lain?) Untuk digunakan di Java. Tentu saja ini juga TIDAK platform independen.

Jika ada yang mengetahui orang lain, silakan komentar, dan saya akan menambahkannya ke daftar ini.

gagarwa
sumber
0

Meskipun bahasa Java tidak secara langsung mendukung kelebihan operator, Anda dapat menggunakan plugin Manifold compiler di proyek Java apa saja untuk mengaktifkannya. Ini mendukung Java 8 - 13 (versi Java saat ini) dan didukung penuh di IntelliJ IDEA.

Scott
sumber