Saya telah merenungkan mengapa Java dan C # (dan saya yakin bahasa lain) default untuk referensi kesetaraan ==
.
Dalam pemrograman yang saya lakukan (yang tentunya hanya sebagian kecil dari masalah pemrograman), saya hampir selalu menginginkan kesetaraan logis ketika membandingkan objek daripada referensi kesetaraan. Saya mencoba memikirkan mengapa kedua bahasa ini menempuh rute ini alih-alih membalikkannya dan memiliki ==
kesetaraan logis dan menggunakan .ReferenceEquals()
persamaan referensi.
Jelas menggunakan kesetaraan referensi sangat sederhana untuk diterapkan dan memberikan perilaku yang sangat konsisten, tetapi sepertinya tidak cocok dengan sebagian besar praktik pemrograman yang saya lihat hari ini.
Saya tidak ingin terlihat acuh terhadap masalah dengan mencoba menerapkan perbandingan logis, dan itu harus diimplementasikan di setiap kelas. Saya juga menyadari bahwa bahasa-bahasa ini telah dirancang sejak lama, tetapi pertanyaan umumnya tetap ada.
Apakah ada beberapa manfaat utama dari gagal dalam hal ini yang hanya saya lewatkan, atau apakah masuk akal bahwa perilaku default harus kesetaraan logis, dan default kembali ke referensi kesetaraan itu kesetaraan logis tidak ada untuk kelas?
sumber
Equals()
, itu tidak secara otomatis mengubah perilaku==
?Jawaban:
C # melakukannya karena Java melakukannya. Java melakukannya karena Java tidak mendukung overloading operator. Karena kesetaraan nilai harus didefinisikan ulang untuk setiap kelas, itu tidak bisa menjadi operator, tetapi harus menjadi metode. IMO ini adalah keputusan yang buruk. Jauh lebih mudah untuk menulis dan membaca
a == b
daripadaa.equals(b)
, dan lebih alami untuk programmer dengan pengalaman C atau C ++, tetapia == b
hampir selalu salah. Bug dari penggunaan==
mana.equals
diperlukan telah menyia-nyiakan ribuan orang dari jam programmer.sumber
==
untuk banyak kelas dan beberapa bulan yang lalu saya menemukan beberapa pengembang tidak tahu apa==
yang sebenarnya dilakukan. Selalu ada risiko ini ketika semantik beberapa konstruk tidak jelas. Theequals()
notasi memberitahu saya bahwa saya menggunakan metode kustom dan bahwa saya harus mencarinya di suatu tempat. Intinya: Saya pikir operator kelebihan adalah masalah terbuka secara umum.+
misalnya, yang melakukan penambahan (nilai numerik) dan rangkaian string pada saat yang sama.a == b
lebih alami bagi programmer dengan pengalaman C, karena C tidak mendukung overloading operator yang ditentukan pengguna? (Misalnya, cara C untuk membandingkan string adalahstrcmp(a, b) == 0
, tidaka == b
.)char *
. Tampak jelas bagi saya bahwa membandingkan dua petunjuk untuk kesetaraan tidak sama dengan perbandingan string.Jawaban singkatnya: Konsistensi
Untuk menjawab pertanyaan Anda dengan benar, saya sarankan kita mengambil langkah mundur dan melihat ke masalah apa arti kesetaraan dalam bahasa pemrograman. Setidaknya ada TIGA kemungkinan yang berbeda, yang digunakan dalam berbagai bahasa:
Ketiga jenis kesetaraan ini sering digunakan karena mudah untuk diimplementasikan: ketiga pemeriksaan kesetaraan dapat dengan mudah dihasilkan oleh kompiler (dalam kasus kesetaraan yang mendalam, kompiler mungkin perlu menggunakan bit tag untuk mencegah loop tak terbatas jika struktur untuk dibandingkan memiliki referensi melingkar). Tetapi ada masalah lain: tidak ada yang cocok.
Dalam sistem non-sepele, kesetaraan objek sering didefinisikan sebagai sesuatu antara kesetaraan yang mendalam dan referensi. Untuk memeriksa apakah kita ingin menganggap dua objek sama dalam konteks tertentu, kita mungkin memerlukan beberapa atribut untuk dibandingkan dengan di mana ia berada dalam memori dan yang lainnya dengan kesetaraan yang mendalam, sementara beberapa atribut mungkin dibiarkan menjadi sesuatu yang berbeda sama sekali. Apa yang benar-benar kita inginkan adalah “jenis kesetaraan yang maju”, yang benar-benar menyenangkan, yang sering disebut dalam keseragaman semantik sastra . Semuanya sama jika sama, di domain kami. =)
Jadi kami dapat kembali ke pertanyaan Anda:
Apa yang kita maksudkan ketika kita menulis 'a == b' dalam bahasa apa pun? Idealnya, harus selalu sama: kesetaraan semantik. Tapi itu tidak mungkin.
Salah satu pertimbangan utama adalah bahwa, setidaknya untuk tipe sederhana seperti angka, kami berharap bahwa dua variabel sama setelah penugasan dengan nilai yang sama. Lihat di bawah:
Dalam hal ini, kami berharap bahwa 'a sama dengan b' dalam kedua pernyataan. Yang lainnya akan menjadi gila. Sebagian besar (jika tidak semua) dari bahasa mengikuti konvensi ini. Oleh karena itu, dengan tipe sederhana (nilai alias) kita tahu cara mencapai kesetaraan semantik. Dengan benda, itu bisa menjadi sesuatu yang sangat berbeda. Lihat di bawah:
Kami berharap yang pertama 'jika' akan selalu benar. Tapi apa yang Anda harapkan pada 'jika' yang kedua? Itu sangat tergantung. Bisakah 'DoSomething' mengubah kesetaraan (semantik) a dan b?
Masalah dengan persamaan semantik adalah bahwa itu tidak dapat secara otomatis dihasilkan oleh kompiler untuk objek, juga tidak jelas dari tugas . Mekanisme harus disediakan bagi pengguna untuk mendefinisikan kesetaraan semantik. Dalam bahasa berorientasi objek, mekanisme itu adalah metode yang diwariskan: sama dengan . Membaca sepotong kode OO, kami tidak mengharapkan metode untuk memiliki implementasi yang persis sama di semua kelas. Kami terbiasa dengan warisan dan kelebihan.
Namun, dengan operator, kami mengharapkan perilaku yang sama. Ketika Anda melihat 'a == b' Anda harus mengharapkan jenis persamaan yang sama (dari 4 di atas) dalam semua situasi. Jadi, dengan tujuan untuk konsistensi , desainer bahasa menggunakan referensi kesetaraan untuk semua jenis. Seharusnya tidak tergantung pada apakah seorang programmer telah menimpa metode atau tidak.
PS: Bahasa Dee sedikit berbeda dari Java dan C #: operator sama berarti persamaan dangkal untuk tipe sederhana dan persamaan semantik untuk kelas yang ditentukan pengguna (dengan tanggung jawab untuk mengimplementasikan = operasi yang terletak pada pengguna - tidak ada standar yang disediakan). Karena, untuk tipe sederhana, persamaan dangkal selalu merupakan persamaan semantik, bahasanya konsisten. Namun, harga yang harus dibayar adalah bahwa operator yang sama secara default tidak ditentukan untuk tipe yang ditentukan pengguna. Anda harus mengimplementasikannya. Dan, terkadang, itu hanya membosankan.
sumber
When you see ‘a == b’ you should expect the same type of equality (from the 4 above) in all situations.
Perancang bahasa Jawa menggunakan referensi kesetaraan untuk objek dan kesetaraan semantik untuk primitif. Tidak jelas bagi saya bahwa ini adalah keputusan yang tepat, atau bahwa keputusan ini lebih "konsisten" daripada membiarkan==
kelebihan muatan untuk kesamaan objek semantik.a
danb
merupakan tipe yang sama, ekspresia==b
menguji apakaha
danb
menahan hal yang sama. Jika salah satu dari mereka memegang referensi ke objek # 291, dan yang lainnya memegang referensi ke objek # 572, mereka tidak memegang hal yang sama. The isi dari objek # 291 dan # 572 mungkin setara, tetapi variabel sendiri memegang hal yang berbeda.a == b
dan tahu apa fungsinya. Demikian juga, Anda dapat melihata.equals(b)
dan menganggap itu kelebihanequals
. Jikaa == b
panggilana.equals(b)
(jika dilaksanakan), apakah itu membandingkan dengan referensi atau dengan konten? Tidak ingat Anda harus memeriksa kelas A. Kode ini tidak lagi cepat dibaca jika Anda bahkan tidak yakin apa yang dipanggil. Ini akan seolah-olah metode dengan tanda tangan yang sama diizinkan, dan metode yang dipanggil tergantung pada apa ruang lingkup saat ini. Program semacam itu tidak mungkin dibaca.Karena pendekatan yang terakhir akan membingungkan. Mempertimbangkan:
Haruskah kode ini dicetak
"ok"
, atau haruskah dilemparkanNullPointerException
?sumber
Untuk Java dan C # manfaatnya terletak pada mereka yang berorientasi objek.
Dari sudut pandang kinerja - kode yang lebih mudah untuk ditulis juga harus lebih cepat: karena OOP bermaksud untuk elemen yang berbeda secara logis untuk diwakili oleh objek yang berbeda, memeriksa kesetaraan referensi akan lebih cepat, dengan mempertimbangkan bahwa objek dapat menjadi cukup besar.
Dari sudut pandang logis - kesetaraan suatu objek dengan yang lain tidak harus sejelas membandingkan dengan properti objek untuk kesetaraan (mis. Bagaimana null == null ditafsirkan secara logis? Ini dapat berbeda dari kasus ke kasus).
Saya pikir apa yang menjadi intinya, adalah pengamatan Anda bahwa "Anda selalu menginginkan kesetaraan logis atas kesetaraan referensi". Konsensus di antara perancang bahasa mungkin sebaliknya. Saya pribadi merasa sulit untuk mengevaluasi ini, karena saya tidak memiliki spektrum pengalaman pemrograman yang luas. Secara kasar, saya lebih banyak menggunakan kesetaraan referensi dalam algoritme pengoptimalan, dan kesetaraan logis lebih banyak dalam menangani kumpulan data.
sumber
.equals()
membandingkan variabel dengan isinya. alih-alih==
membandingkan objek dengan isinya ...menggunakan objek lebih akurat untuk digunakan
.equals()
sumber