Semua proses desain menghasilkan kompromi antara tujuan yang saling tidak kompatibel. Sayangnya, proses desain untuk &&
operator yang kelebihan beban di C ++ menghasilkan hasil akhir yang membingungkan: bahwa fitur yang Anda inginkan &&
- perilaku hubung singkatnya - dihilangkan.
Detail tentang bagaimana proses desain itu berakhir di tempat malang ini, yang tidak saya ketahui. Namun relevan untuk melihat bagaimana proses desain selanjutnya memperhitungkan hasil yang tidak menyenangkan ini. Di C #, &&
operator yang kelebihan beban mengalami korsleting. Bagaimana para desainer C # mencapai itu?
Salah satu jawaban lain menyarankan "pengangkatan lambda". Itu adalah:
A && B
dapat diwujudkan sebagai sesuatu yang secara moral setara dengan:
operator_&& ( A, ()=> B )
dimana argumen kedua menggunakan beberapa mekanisme untuk evaluasi malas sehingga ketika dievaluasi, efek samping dan nilai ekspresi yang dihasilkan. Implementasi dari operator yang kelebihan beban hanya akan melakukan evaluasi malas jika diperlukan.
Ini bukanlah yang dilakukan oleh tim desain C #. (Selain: meskipun pengangkatan lambda adalah apa yang saya lakukan ketika tiba waktunya untuk melakukan representasi pohon ekspresi dari ??
operator, yang memerlukan operasi konversi tertentu untuk dilakukan dengan malas. Menjelaskan bahwa secara detail akan menjadi penyimpangan besar. Cukup untuk dikatakan: pengangkatan lambda berfungsi tetapi cukup kelas berat sehingga kami ingin menghindarinya.)
Sebaliknya, solusi C # memecah masalah menjadi dua masalah terpisah:
- haruskah kita mengevaluasi operan kanan?
- jika jawaban di atas adalah "ya", lalu bagaimana kita menggabungkan kedua operan tersebut?
Oleh karena itu, masalah diselesaikan dengan membuatnya ilegal untuk membebani &&
secara langsung. Sebaliknya, di C # Anda harus membebani dua operator, yang masing-masing menjawab salah satu dari dua pertanyaan tersebut.
class C
{
public static bool operator false (C c) { whatever }
public static C operator & (C left, C right) { whatever }
...
(Selain: sebenarnya, tiga. C # mensyaratkan bahwa jika operator false
disediakan maka operator true
juga harus disediakan, yang menjawab pertanyaan: apakah hal ini "benar-benar?". Biasanya tidak ada alasan untuk menyediakan hanya satu operator tersebut jadi C # membutuhkan keduanya.)
Pertimbangkan pernyataan dalam bentuk:
C cresult = cleft && cright;
Kompilator menghasilkan kode untuk ini seperti yang Anda kira Anda telah menulis pseudo-C ini #:
C cresult;
C tempLeft = cleft;
cresult = C.false(tempLeft) ? tempLeft : C.&(tempLeft, cright);
Seperti yang Anda lihat, sisi kiri selalu dievaluasi. Jika ditentukan sebagai "false-ish" maka itulah hasilnya. Jika tidak, sisi kanan dievaluasi, dan operator yang ditentukan pengguna yang bersemangat&
dipanggil.
The ||
Operator didefinisikan dalam cara analog, sebagai doa operator yang benar dan bersemangat |
Operator:
cresult = C.true(tempLeft) ? tempLeft : C.|(tempLeft , cright);
Dengan mendefinisikan semua empat operator - true
, false
, &
dan |
- C # memungkinkan Anda untuk tidak hanya mengatakan cleft && cright
tetapi juga non-hubungan arus pendek cleft & cright
, dan juga if (cleft) if (cright) ...
, dan c ? consequence : alternative
dan while(c)
, dan sebagainya.
Sekarang, saya mengatakan bahwa semua proses desain adalah hasil kompromi. Di sini perancang bahasa C # berhasil mendapatkan hubungan arus pendek &&
dan ||
kanan, tetapi melakukan hal itu memerlukan kelebihan beban empat operator, bukan dua , yang membingungkan beberapa orang. Fitur benar / salah operator adalah salah satu fitur yang paling tidak dipahami dengan baik di C #. Tujuan memiliki bahasa yang masuk akal dan lugas yang akrab bagi pengguna C ++ ditentang oleh keinginan untuk mengalami korsleting dan keinginan untuk tidak mengimplementasikan lambda lifting atau bentuk evaluasi malas lainnya. Saya pikir itu adalah posisi kompromi yang masuk akal, tetapi penting untuk disadari bahwa itu adalah posisi kompromi. Hanya berbeda posisi kompromi daripada desainer C ++ mendarat.
Jika subjek desain bahasa untuk operator semacam itu menarik minat Anda, pertimbangkan untuk membaca seri saya tentang mengapa C # tidak mendefinisikan operator ini pada nullable Boolean:
http://ericlippert.com/2012/03/26/null-is-not-false-part-one/
operator&&(const Foo& lhs, const Foo& rhs) : (lhs.bars == 0)