Mengapa ada variasi hubung-pendek ATAU maupun hubung singkat dari operator itu di C #?

9

Secara berkala, saya bertanya-tanya tentang ini:

Hubung-pendek ATAU akan selalu mengembalikan nilai yang sama dengan yang akan dilakukan oleh operator ATAU unortort?

Saya berharap bahwa hubungan arus pendek ATAU akan selalu mengevaluasi lebih cepat. Jadi, apakah operator OR yang tidak bersirkulasi pendek termasuk dalam bahasa C # untuk konsistensi?

Apa yang saya lewatkan?

CarneyCode
sumber
9
Nilai pengembalian yang sama - ya. Efek samping yang sama - tidak.
Pekerjaan
2
Misalkan f()menimbulkan pengecualian, pertimbangkan true || f()dan true | f(). Apakah Anda melihat perbedaannya? Ekspresi mantan mengevaluasi true, evaluasi yang terakhir menghasilkan pengecualian yang dilemparkan.
scarfridge

Jawaban:

25

Kedua operan dimaksudkan untuk hal yang berbeda, berasal dari C yang tidak memiliki tipe boolean. Versi hubung singkat || hanya bekerja dengan boolean, sedangkan versi hubung singkat | bekerja dengan tipe integral, melakukan bitwise atau. Itu hanya terjadi untuk bekerja sebagai operasi logis hubung singkat untuk boolean yang diwakili oleh bit tunggal, menjadi 0 atau 1.

http://en.wikibooks.org/wiki/C_Sharp_Programming/Operators#Logical

Aman
sumber
10
+1 untuk tautan. Ketika saya membaca pertanyaan ini, saya seperti "apa?" karena afaik nama resmi ini logis dan bitwise atau, dan bukan hubungan pendek dan tidak pendek yang kebetulan merupakan efek samping dari cara kerjanya.
stijn
1
+1 Saya melihat "beroperasi hanya pada operan boolean" - Saya mungkin tidak melihat perbedaannya karena saya hanya menggunakan ekspresi yang mengevaluasi ke Boolean
CarneyCode
2
Saya harus memeriksa, tetapi memang benar bahwa |operator, ketika diterapkan pada dua nilai boolean, dikompilasi ke dalam oroperator yang sama di CIL seperti ketika diterapkan pada dua nilai integer - tidak seperti ||yang dikompilasi ke dalam CIL menggunakan brtruekondisional melompat.
quentin-starin
13

|(bitwise-atau) harus bukan hubung singkat untuk tipe seperti int. Itu karena di hampir semua kasus, Anda perlu menghitung kedua sisi |ekspresi untuk menghitung hasil yang benar. Misalnya, apa hasilnya 7 | f(x)?

Jika f(x)tidak dievaluasi, Anda tidak tahu.

Lebih jauh lagi, akan menjadi tidak konsisten untuk membuat hubung singkat bagi operator ini bool, ketika itu adalah hubung singkat untuk int. Ngomong-ngomong, saya pikir saya tidak pernah |sengaja menggunakan perbandingan logis, merasa sangat tidak nyaman untuk berbicara |sebagai operator yang logis.

|| namun untuk perbandingan logis, di mana evaluasi hubung singkat berfungsi dengan baik.

Hal yang sama berlaku bahkan untuk C dan C ++, di mana asal dari operator tersebut.

Doc Brown
sumber
5

Ini benar, operator OR hubung singkat (||) akan selalu mengembalikan nilai yang sama dengan operator OR hubung-pendek (|). (*)

Namun, jika operan pertama benar, operator hubung singkat tidak akan menyebabkan evaluasi operan kedua, sedangkan operator non-hubung singkat akan selalu menyebabkan evaluasi kedua operan. Ini dapat berdampak pada kinerja, dan kadang-kadang dalam efek samping.

Jadi, ada gunanya untuk keduanya: jika Anda peduli untuk kinerja, dan evaluasi operan kedua tidak menghasilkan efek samping, (atau jika Anda tidak peduli tentang mereka), maka tentu saja gunakan operator hubung singkat . Tetapi jika karena alasan tertentu Anda memerlukan efek samping dari operan kedua, maka Anda harus menggunakan operator hubung singkat.

Contoh di mana Anda harus menggunakan operator hubung singkat:

if( write_customer_to_database() != SUCCESS |
    write_supplier_to_database() != SUCCESS |
    write_order_to_database() != SUCCESS )
{
    transaction_rollback();
}

(*) Kecuali untuk beberapa skenario yang benar-benar menyimpang di mana evaluasi operan pertama menjadi penyebab salah dengan efek samping operan kedua untuk mengevaluasi ke true, bukan false.

Mike Nakis
sumber
2
+1 Tapi saya ingin menambahkan bahwa selain menggunakan fungsi untuk menunjukkan keberhasilan atau kegagalan (seperti dalam contoh Anda): fungsi dengan efek samping umumnya harus dihindari ...
Marjan Venema
1
Ya, mungkin itulah sebabnya saya tidak pernah menggunakan salah satu operator hubung singkat hingga hari ini, dan kemungkinannya kecil sekali.
Mike Nakis
Contoh itu tergantung pada operan yang dievaluasi dalam urutan kiri-ke-kanan yang ketat. C # memang menjamin hal ini, tetapi banyak bahasa yang serupa (termasuk C dan C ++) tidak.
Keith Thompson
Bukankah evaluasi arus pendek masuk akal untuk contoh khusus itu, karena semua transaksi akan dibatalkan jika ada yang gagal? (Saya membuat beberapa asumsi tentang semantik panggilan itu.)
Keith Thompson
@KeithThompson Anda benar, evaluasi non-hubung singkat akan menyebabkan pemrosesan yang tidak perlu, dan dalam hal ini contohnya adalah sedikit timpang, tetapi tidak begitu timpang untuk menjamin perubahan, karena kebenaran tetap dengan evaluasi hubung singkat jika write_customer_to_database () berhasil, maka sisa fungsi tulis _... tidak akan pernah dipanggil, dan lebih baik bekerja dengan benar dalam hal kesuksesan, daripada melakukan beberapa operasi yang tidak perlu dalam kasus kegagalan.
Mike Nakis
4

Akan ada 2 alasan untuk menggunakan varian non-shortcircuit:

  1. menjaga efek samping (tapi itu lebih jelas untuk dikodekan dengan variabel sementara)

  2. menggagalkan serangan waktu dengan menghindari garpu di hubung singkat (ini bahkan dapat meningkatkan efisiensi runtime jika operan kedua adalah variabel tetapi itu adalah mikro-optimasi yang mungkin dilakukan kompiler)

aneh ratchet
sumber
Ini adalah satu-satunya alasan yang tepat disediakan, saya tidak tahu mengapa ini bukan jawaban yang diterima dengan suara tertinggi ...
Behrooz
2

jika klausa kanan operator memiliki efek samping, dan pemrogram bermaksud bahwa ia ingin kedua efek samping terjadi sebelum memeriksa nilai pengembaliannya.

Lie Ryan
sumber
5
Eek. Tolong jangan kode seperti itu ... jika Anda mengandalkan efek samping, memiliki dua ekspresi yang berbeda, menetapkan hasilnya, dan mengujinya setelah itu .
Konrad Rudolph