Apakah ada alasan teknis untuk menggunakan> (<) alih-alih! = Ketika bertambah 1 dalam loop 'untuk'?


198

Saya hampir tidak pernah melihat forlingkaran seperti ini:

for (int i = 0; 5 != i; ++i)
{}

Apakah ada alasan teknis untuk digunakan >atau <alih-alih !=ketika bertambah 1 dalam satu forlingkaran? Atau ini lebih dari sebuah konvensi?


104
Itu membuatnya lebih mudah dibaca, ditambah, jika Anda pernah berubah i++menjadi i+=2(misalnya), itu akan berjalan untuk waktu yang sangat lama (atau mungkin selamanya). Sekarang, karena Anda biasanya menggunakan <untuk kasus-kasus di mana Anda meningkatkan iterator lebih dari 1, Anda mungkin juga menggunakan <untuk kasus di mana Anda menambahnya dengan 1 (untuk konsistensi).
barak manos

112
5 != iitu jahat
Slava

27
Anda harus selalu sadar akan apa yang Anda lakukan, tetapi Anda tetap akan membuat kesalahan. Menggunakan <mengurangi kemungkinan seseorang memperkenalkan bug ke dalam kode ini.
Aurast

40
@OleTange Jika Anda melakukan iterasi menggunakan angka floating point Anda sudah kacau ..
CaptainCodeman

29
@Slava ... tidak jahat. Anda tampaknya belum pernah menggigit C oleh kesalahan ketik sederhana yang membuat perbedaan antara if ( i == 5 ) ...dan if ( i = 5 ). Hal yang sangat berbeda. Membalik operan mencegah masalah: karena literal tidak lvals, mereka tidak dapat ditugaskan dan kompiler melemparkan pada kesalahan ketik. @Zingam: pemrograman defensif yang bagus!
Nicholas Carey

Jawaban:


303
while (time != 6:30pm) {
    Work();
}

Sekarang jam 6:31 sore ... Sial, sekarang kesempatan berikutnya untuk pulang adalah besok! :)

Ini untuk menunjukkan bahwa pembatasan yang lebih kuat memitigasi risiko dan mungkin lebih intuitif untuk dipahami.


25
Terkadang, mencoba untuk "mengurangi risiko" akhirnya menyembunyikan bug. Jika desain loop harus mencegah 6:30 dari tergelincir oleh tanpa disadari, maka menggunakan <akan menyembunyikan bug tetapi menggunakan !=akan membuat jelas bahwa ada masalah.
Adrian McCarthy

27
@AdrianMcCarthy: Belum tentu; itu hanya bisa memperkenalkan bug kedua, membuat diagnosis lebih sulit .
Lightness Races in Orbit

4
@AdrianMcCarthy: Itu maksud saya; Anda bisa memiliki beberapa contohnya yang belum Anda lihat;)
Lightness Races in Orbit

6
Iterator adalah contoh sempurna dari titik @AdrianMcCarthy. Perbandingan yang disarankan untuk mereka adalah! = Bukannya <.
Taekahn

5
Saya telah melihat persis kesalahan ini (dan itu menyebabkan debugging 3 bulan) - tetapi jawaban ini sepenuhnya melenceng. Dalam contoh yang diberikan itu tidak mungkin untuk kondisi akhir untuk dilewatkan. Anda bahkan bisa mengatakan bahwa untuk secara sadar memilih! = Lebih dari <adalah membuat pernyataan yang kuat tentang fakta ini. Mengurangi risiko yang secara definitif tidak ada adalah bau kode bagi saya. (Karena itu, Anda dapat juga berpendapat bahwa <adalah idiomatik, bahwa itu adalah alasan yang baik untuk menggunakannya seperti apa pun.)
Ian Goldby

95

Tidak ada alasan teknis. Tetapi ada mitigasi risiko, rawatan dan pemahaman kode yang lebih baik.

<atau >pembatasan yang lebih kuat daripada !=dan memenuhi tujuan yang sama persis dalam banyak kasus (saya bahkan akan mengatakan dalam semua kasus praktis).

Ada pertanyaan rangkap di sini ; dan satu jawaban yang menarik .


6
Ada beberapa jenis, seperti iterator, yang tidak mendukung <atau>, tetapi mendukung == dan! =.
Simon B

1
Ini untuk loop dengan int . Tidak ada iterator.
Ely

7
"Tapi ada mitigasi risiko, rawatan dan pemahaman kode yang lebih baik." Semua itu, dengan tepat, merupakan alasan teknis. :-)
TJ Crowder

@TJCrowder Apa jenis alasannya ketika Anda hanya ingin berbicara tentang apa yang akan dilakukan mesin sebagai hasilnya?
Brilliand

1
@DanSheppard Saya biasanya akan mempertimbangkan mitigasi risiko dan pemeliharaan untuk menjadi alasan bisnis, dan pemahaman kode yang lebih baik menjadi alasan sosial (meskipun semua alasan itu diterapkan pada masalah teknis dalam kasus ini). Pertimbangan "Mitigasi risiko" sama sekali tidak terbatas pada masalah teknis, dan pertimbangan "pemahaman kode yang lebih baik" dapat berubah jika Anda menemukan diri Anda bekerja dengan kelompok orang yang berbeda (bahkan jika mesin yang terlibat tidak berubah sama sekali. ).
Brilliand

85

Ya ada alasannya. Jika Anda menulis (berbasis indeks lama polos) untuk loop seperti ini

for (int i = a; i < b; ++i){}

maka itu berfungsi seperti yang diharapkan untuk nilai apa pun dari adan b(yaitu nol iterasi ketika a > bbukannya tak terbatas jika Anda telah menggunakan i == b;).

Di sisi lain, untuk iterator Anda akan menulis

for (auto it = begin; it != end; ++it) 

karena setiap iterator harus mengimplementasikan suatu operator!=, tetapi tidak untuk setiap iterator dimungkinkan untuk menyediakan operator<.

Juga berbasis rentang untuk loop

for (auto e : v)

bukan hanya gula mewah, tetapi mereka secara terukur mengurangi peluang untuk menulis kode yang salah.


4
Contoh yang bagus. Saya akan tertarik pada kasus untuk !=bukannya <. Saya pribadi tidak pernah menggunakan yang saya pikir.
Ely

@ Elyasin Saya tidak menemukan yang baik, dan saya tidak ingin memposting yang buruk: Bayangkan Anda memiliki semacam wadah bundar, di mana Anda menambah + x modulo ukuran wadah N dan Anda ingin menghentikan lingkaran ketika Anda mencapai indeks tertentu .... well itu contoh yang sangat buruk. Mungkin saya akan menemukan yang lebih baik
idclev 463035818

Lingkaran yang sama dengan! = Bukannya <memperjelas apa keuntungan <(atau>) dalam konteks ini. for (int i=a; i != b; i++) {}
Paul Smith

10
Menggunakan apa pun selain !=dengan iterator cukup berbahaya, karena kadang - kadang iterator dapat lebih sedikit dibandingkan (misalnya pointer) tetapi perbandingannya tidak ada artinya (ini adalah daftar tertaut).
Zan Lynx

1
Belajarlah untuk menggunakan ruang putih, dengan serius.
Miles Rout

70

Anda dapat memiliki sesuatu seperti

for(int i = 0; i<5; ++i){
    ...
    if(...) i++;
    ...
}

Jika variabel loop Anda ditulis oleh kode bagian dalam, variabel tersebut i!=5mungkin tidak memecah loop tersebut. Ini lebih aman untuk memeriksa ketimpangan.

Edit tentang keterbacaan. Bentuk ketimpangan jauh lebih sering digunakan. Oleh karena itu, ini sangat cepat dibaca karena tidak ada yang istimewa untuk dipahami (beban otak berkurang karena tugasnya sama). Jadi keren bagi pembaca untuk memanfaatkan kebiasaan ini.


6
Jenis batin "jika (kondisi) maka saya ++" adalah hal pertama yang saya pikirkan.
WernerCD

3
Datang dalam mengharapkan ini menjadi jawaban pilihan tertinggi; Saya terkejut bahwa saya harus menggulir sejauh ini untuk menemukannya. Ini lebih banyak meyakinkan meyakinkan programmer pemula daripada "well, Anda harus menggunakan kondisi terkuat". Jawaban lain, jika mereka tetap di atas, harus memasukkan ini sebagai penjelasan yang jelas dan jelas tentang apa yang bisa salah dengan kode yang diusulkan OP.
msouth

1
@msouth Saya sepenuhnya setuju, tetapi POV saya cukup subyektif;)
johan d

3
@msouth Saya suka ketika perilaku produksi yang tidak terduga mengekspos bug saya, bukan? :-)
deworde

3
@ Mulut Dengar, yang harus kita lakukan adalah jangan pernah melakukan kesalahan dan semuanya akan baik-baik saja Sederhana.
deworde

48

Dan last but not least, ini disebut pemrograman defensif , yang berarti untuk selalu mengambil kasus terkuat untuk menghindari kesalahan saat ini dan masa depan yang mempengaruhi program.

Satu-satunya kasus di mana pemrograman defensif tidak diperlukan adalah di mana negara telah dibuktikan oleh pra dan pasca-kondisi (tapi kemudian, membuktikan ini adalah yang paling defensif dari semua pemrograman).


2
Satu contoh yang baik untuk mendukung ini: Memori rentan terhadap bit flips ( SEUs ) yang disebabkan oleh radiasi. Ketika menggunakan suatu intuntuk suatu i != 15kondisi, penghitung akan berjalan untuk waktu yang lama jika ada sesuatu di atas bit keempat dibalik, terutama pada mesin sizeof(int)yang 64. , atau dalam superkomputer besar (karena begitu banyak memori yang ada).
Josh Sanford

2
Berpikir bahwa program Anda akan berjalan baik ketika radiasi mengubah ingatan Anda adalah cara yang optimis dan cara berpikir anti-bencana ... komentar yang bagus! :)
Luis Colorado

37

Saya berpendapat bahwa ungkapan itu seperti

for ( int i = 0 ; i < 100 ; ++i )
{
  ...
}

lebih ekspresif dari niat daripada apa adanya

for ( int i = 0 ; i != 100 ; ++i )
{
  ...
}

Yang pertama dengan jelas menyatakan bahwa kondisi tersebut merupakan ujian untuk batas atas eksklusif pada rentang; yang terakhir adalah tes biner dari kondisi keluar. Dan jika badan loop adalah non-sepele, mungkin tidak jelas bahwa indeks hanya dimodifikasi dalam forpernyataan itu sendiri.


13
"Saya ingin loop ini berjalan paling banyak 5 kali" vs. "Saya ingin menjalankan loop ini sebanyak yang diperlukan, kecuali tepat 5 kali, yang saya tidak inginkan."
Uskup

+1 untuk menyebutkan batas atas pada rentang. Saya pikir ini penting untuk rentang numerik. ! = tidak mendefinisikan rentang yang tepat dalam for for loop seperti ini
element11

22

Iterator adalah kasus penting ketika Anda paling sering menggunakan !=notasi:

for(auto it = vector.begin(); it != vector.end(); ++it) {
 // do stuff
}

Memang: dalam praktiknya saya akan menulis hal yang sama dengan mengandalkan range-for:

for(auto & item : vector) {
 // do stuff
}

tetapi intinya tetap: orang biasanya membandingkan iterator menggunakan ==atau !=.


2
Iterator seringkali hanya memiliki gagasan tentang persamaan / ketidaksetaraan dan bukan urutan, itulah mengapa Anda menggunakannya !=untuk mereka. Misalnya, dalam std::vectorAnda dapat menggunakan <sebagai iterator terikat ke indeks / pointer, tetapi dalam std::settidak ada urutan yang ketat, karena berjalan pohon biner.
Martin C.

19

Kondisi loop adalah invarian loop yang dipaksakan.

Misalkan Anda tidak melihat isi loop:

for (int i = 0; i != 5; ++i)
{
  // ?
}

dalam hal ini, Anda tahu pada awal iterasi loop yang itidak sama 5.

for (int i = 0; i < 5; ++i)
{
  // ?
}

dalam hal ini, Anda tahu pada awal iterasi loop yang ikurang dari5 .

Yang kedua jauh, jauh lebih banyak informasi daripada yang pertama, bukan? Sekarang, maksud programmer adalah (hampir pasti) sama, tetapi jika Anda mencari bug, memiliki kepercayaan diri dari membaca baris kode adalah hal yang baik. Dan yang kedua menegakkan invarian itu, yang berarti beberapa bug yang akan menggigit Anda dalam kasus pertama tidak dapat terjadi (atau tidak menyebabkan kerusakan memori, katakanlah) dalam kasus kedua.

Anda tahu lebih banyak tentang keadaan program, dari membaca lebih sedikit kode, <daripada dengan!= . Dan pada CPU modern, mereka mengambil jumlah waktu yang sama karena tidak ada perbedaan.

Jika Anda itidak dimanipulasi dalam tubuh loop, dan itu selalu meningkat sebesar 1, dan itu mulai kurang dari5 , tidak akan ada perbedaan. Tetapi untuk mengetahui apakah itu dimanipulasi, Anda harus mengkonfirmasi masing-masing fakta ini.

Beberapa fakta ini relatif mudah, tetapi Anda bisa salah. Namun, memeriksa seluruh tubuh loop itu menyebalkan.

Di C ++ Anda bisa menulis indexestipe seperti itu:

for( const int i : indexes(0, 5) )
{
  // ?
}

melakukan hal yang sama seperti salah satu dari dua forloop di atas , bahkan ke kompiler mengoptimalkannya ke kode yang sama. Di sini, bagaimanapun, Anda tahu bahwa itidak dapat dimanipulasi dalam tubuh loop, seperti yang dinyatakan const, tanpa kode merusak memori.

Semakin banyak informasi yang Anda dapatkan dari satu baris kode tanpa harus memahami konteksnya, semakin mudah melacak apa yang salah. <dalam hal bilangan bulat loop memberi Anda lebih banyak informasi tentang keadaan kode di baris itu daripada yang !=dilakukan.



13

Ini mungkin terjadi bahwa variabel idiatur ke beberapa nilai besar dan jika Anda hanya menggunakan !=operator Anda akan berakhir dalam loop tanpa akhir.


1
Tidak benar-benar tak ada habisnya - pada sebagian besar implementasi C, idiam-diam akan membungkus ketika maksimal. Tapi ya, kemungkinan besar lebih lama dari yang Anda siap tunggu.
usr2564301

12

Seperti yang dapat Anda lihat dari banyak jawaban lainnya, ada alasan untuk menggunakan <daripada! = Yang akan membantu dalam kasus tepi, kondisi awal, modifikasi penghitung putaran yang tidak diinginkan, dll ...

Jujur saja, saya tidak berpikir Anda bisa menekankan pentingnya konvensi. Untuk contoh ini akan cukup mudah bagi programmer lain untuk melihat apa yang Anda coba lakukan, tetapi itu akan menyebabkan pengambilan ganda. Salah satu pekerjaan saat pemrograman membuatnya menjadi dapat dibaca dan akrab bagi semua orang mungkin, jadi pasti ketika seseorang harus memperbarui / mengubah kode Anda, tidak perlu banyak usaha untuk mencari tahu apa yang Anda lakukan dalam blok kode yang berbeda . Jika saya melihat seseorang menggunakan !=, saya akan berasumsi ada alasan mereka menggunakannya bukan <dan jika itu adalah loop besar saya akan melihat seluruh hal mencoba untuk mencari tahu apa yang Anda lakukan yang membuat itu perlu ... dan itu membuang-buang waktu.


12

Seperti yang sudah dikatakan oleh Ian Newson, Anda tidak bisa dengan andal mengulang variabel mengambang dan keluar bersama !=. Misalnya,

for (double x=0; x!=1; x+=0.1) {}

benar-benar akan berulang selamanya, karena 0,1 tidak dapat secara tepat diwakili dalam floating point, maka penghitungnya akan meleset 1. With < itu berakhir.

(Namun perlu dicatat bahwa pada dasarnya itu adalah perilaku yang tidak ditentukan apakah Anda mendapatkan 0,9999 ... sebagai nomor yang diterima terakhir - jenis pelanggaran yang kurang dari asumsi - atau sudah keluar di 1,0000000000000001000).


10

Saya mengambil kata sifat "teknis" berarti perilaku bahasa / keanehan dan efek samping kompiler seperti kinerja kode yang dihasilkan.

Untuk tujuan ini, jawabannya adalah: tidak (*). (*) Adalah "silakan baca manual prosesor Anda". Jika Anda bekerja dengan sistem RISC atau FPGA case-edge, Anda mungkin perlu memeriksa instruksi apa yang dihasilkan dan berapa biayanya. Tapi jika Anda menggunakan hampir semua arsitektur modern konvensional, maka tidak ada perbedaan tingkat prosesor yang signifikan dalam biaya antara lt, eq, nedan gt.

Jika Anda menggunakan kasus tepi Anda bisa menemukan bahwa !=memerlukan tiga operasi ( cmp, not, beq) vs dua ( cmp,blt xtr myo ). Sekali lagi, RTM dalam hal itu.

Sebagian besar, alasannya defensif / pengerasan, terutama ketika bekerja dengan pointer atau loop kompleks. Mempertimbangkan

// highly contrived example
size_t count_chars(char c, const char* str, size_t len) {
    size_t count = 0;
    bool quoted = false;
    const char* p = str;
    while (p != str + len) {
        if (*p == '"') {
            quote = !quote;
            ++p;
        }
        if (*(p++) == c && !quoted)
            ++count;
    }
    return count;
}

Contoh yang kurang dibuat-buat adalah di mana Anda menggunakan nilai balik untuk melakukan peningkatan, menerima data dari pengguna:

#include <iostream>
int main() {
    size_t len = 5, step;
    for (size_t i = 0; i != len; ) {
        std::cout << "i = " << i << ", step? " << std::flush;

        std::cin >> step;
        i += step; // here for emphasis, it could go in the for(;;)
    }
}

Coba ini dan masukkan nilai 1, 2, 10, 999.

Anda dapat mencegah ini:

#include <iostream>
int main() {
    size_t len = 5, step;
    for (size_t i = 0; i != len; ) {
        std::cout << "i = " << i << ", step? " << std::flush;
        std::cin >> step;
        if (step + i > len)
            std::cout << "too much.\n";
        else
            i += step;
    }
}

Tapi yang mungkin Anda inginkan adalah

#include <iostream>
int main() {
    size_t len = 5, step;
    for (size_t i = 0; i < len; ) {
        std::cout << "i = " << i << ", step? " << std::flush;
        std::cin >> step;
        i += step;
    }
}

Ada juga sesuatu yang bias konvensi terhadap <, karena pemesanan dalam wadah standar sering bergantung operator<, misalnya hashing dalam beberapa wadah STL menentukan kesetaraan dengan mengatakan

if (lhs < rhs) // T.operator <
    lessthan
else if (rhs < lhs) // T.operator < again
    greaterthan
else
    equal

Jika lhsdan rhsadalah kelas yang ditentukan pengguna menulis kode ini sebagai

if (lhs < rhs) // requires T.operator<
    lessthan
else if (lhs > rhs) // requires T.operator>
    greaterthan
else
    equal

Implementor harus menyediakan dua fungsi perbandingan. Jadi <sudah menjadi operator yang disukai.


Untuk keterbacaan i + = langkah harus di bagian kontrol. Dalam jika Anda akan melangkah = 0
Mikkel Christiansen

1
Sementara itu akan membantu keterbacaan kode yang baik, saya ingin menekankan cacat pada versi yang salah
kfsone

9

Ada beberapa cara untuk menulis segala jenis kode (biasanya), kebetulan ada dua cara dalam kasus ini (tiga jika Anda menghitung <= dan> =).

Dalam hal ini, orang lebih suka> dan <untuk memastikan bahwa bahkan jika sesuatu yang tidak terduga terjadi dalam loop (seperti bug), itu tidak akan berulang tanpa batas (BAD). Pertimbangkan kode berikut, misalnya.

for (int i = 1; i != 3; i++) {
    //More Code
    i = 5; //OOPS! MISTAKE!
    //More Code
}

Jika kita menggunakan (i <3), kita akan aman dari infinite loop karena menempatkan batasan yang lebih besar.

Ini benar-benar pilihan Anda apakah Anda ingin kesalahan dalam program Anda untuk mematikan semuanya atau tetap berfungsi dengan bug di sana.

Semoga ini bisa membantu!


seseorang dapat berargumen bahwa infinite loop akan menjadi indikator kesalahan yang baik, tetapi kemudian yang lain akan berpendapat bahwa i = 5 belum tentu merupakan kesalahan
njzk2

7

Alasan paling umum untuk digunakan <adalah konvensi. Lebih banyak programmer menganggap loop seperti ini sebagai "ketika indeks berada dalam kisaran" daripada "sampai indeks mencapai akhir." Ada nilai yang menempel pada konvensi ketika Anda bisa.

Di sisi lain, banyak jawaban di sini mengklaim bahwa menggunakan <formulir membantu menghindari bug. Saya berpendapat bahwa dalam banyak kasus ini hanya membantu menyembunyikan bug. Jika indeks loop seharusnya mencapai nilai akhir, dan, sebaliknya, itu benar-benar melampaui itu, maka ada sesuatu yang terjadi yang tidak Anda duga yang dapat menyebabkan kegagalan fungsi (atau menjadi efek samping dari bug lain). The <kemungkinan akan menunda penemuan bug. Itu!= lebih cenderung mengarah ke kios, hang, atau bahkan crash, yang akan membantu Anda menemukan bug lebih cepat. Semakin cepat bug ditemukan, semakin murah untuk memperbaikinya.

Perhatikan bahwa konvensi ini khusus untuk pengindeksan array dan vektor. Saat melintasi hampir semua jenis struktur data lainnya, Anda akan menggunakan iterator (atau pointer) dan memeriksa langsung untuk nilai akhir. Dalam hal ini Anda harus yakin iterator akan mencapai dan tidak melampaui nilai akhir yang sebenarnya.

Misalnya, jika Anda melangkah melalui string C biasa, biasanya lebih umum untuk menulis:

for (char *p = foo; *p != '\0'; ++p) {
  // do something with *p
}

dari

int length = strlen(foo);
for (int i = 0; i < length; ++i) {
  // do something with foo[i]
}

Untuk satu hal, jika string sangat panjang, bentuk kedua akan lebih lambat karena yang strlenlain melewati string.

Dengan string C ++ std ::, Anda akan menggunakan rentang berbasis untuk loop, algoritma standar, atau iterator, meskipun panjangnya tersedia. Jika Anda menggunakan iterator, konvensi ini adalah untuk menggunakan !=daripada <, seperti pada:

for (auto it = foo.begin(); it != foo.end(); ++it) { ... }

Demikian pula, iterasi pohon atau daftar atau deque biasanya melibatkan menonton pointer nol atau sentinel lainnya daripada memeriksa apakah indeks tetap dalam jangkauan.


3
Anda benar untuk menekankan pentingnya idiom dalam pemrograman. Jika saya melihat beberapa kode dan memiliki pola yang umum, saya tidak perlu membuang waktu untuk menyimpulkan polanya, tetapi bisa langsung ke inti dari itu. Saya kira itulah pegangan utama saya dengan perbandingan Yoda - mereka tidak terlihat idiomatis, jadi saya akhirnya harus membacanya dua kali untuk memastikan bahwa mereka memaksudkan apa yang saya pikir mereka maksudkan.
Toby Speight

7

Salah satu alasan untuk tidak menggunakan konstruk ini adalah angka floating point. !=adalah perbandingan yang sangat berbahaya untuk digunakan dengan pelampung karena jarang akan mengevaluasi ke true bahkan jika angkanya terlihat sama. <atau >menghilangkan risiko ini.


Jika loop iterator Anda adalah angka floating point, maka !=lawannya <adalah yang paling sedikit masalah Anda.
Lundin

7

Ada dua alasan terkait untuk mengikuti praktik ini yang keduanya berkaitan dengan fakta bahwa bahasa pemrograman, bagaimanapun, adalah bahasa yang akan dibaca oleh manusia (antara lain).

(1) Sedikit redundansi. Dalam bahasa alami, kami biasanya memberikan lebih banyak informasi daripada yang diperlukan, seperti kode koreksi kesalahan. Di sini informasi tambahannya adalah variabel loop i(lihat bagaimana saya menggunakan redundansi di sini? Jika Anda tidak tahu apa arti 'variabel loop', atau jika Anda lupa nama variabelnya, setelah membaca "variabel loop i", Anda memiliki informasi) kurang dari 5 selama loop, tidak hanya berbeda dari 5. Redundansi meningkatkan keterbacaan.

(2) Konvensi. Bahasa memiliki cara standar spesifik untuk mengekspresikan situasi tertentu. Jika Anda tidak mengikuti cara yang mapan untuk mengatakan sesuatu, Anda masih akan dipahami, tetapi upaya untuk penerima pesan Anda lebih besar karena optimisasi tertentu tidak akan berhasil. Contoh:

Jangan bicara soal mash hot. Terangkan kesulitannya!

Kalimat pertama adalah terjemahan harfiah dari idiom Jerman. Yang kedua adalah idiom bahasa Inggris yang umum dengan kata-kata utama diganti dengan sinonim. Hasilnya dapat dipahami tetapi membutuhkan waktu lebih lama untuk memahami daripada ini:

Jangan bertele-tele. Jelaskan saja masalahnya!

Ini benar bahkan dalam kasus sinonim yang digunakan dalam versi pertama terjadi agar sesuai dengan situasi lebih baik daripada kata-kata konvensional dalam idiom bahasa Inggris. Kekuatan serupa berlaku ketika pemrogram membaca kode. Ini juga mengapa 5 != idan ini 5 > iadalah cara aneh untuk meletakkannya kecuali jika Anda bekerja di lingkungan yang standar untuk bertukar yang lebih normal i != 5dan i < 5dengan cara ini. Komunitas-komunitas dialek semacam itu memang ada, mungkin karena konsistensi membuatnya lebih mudah untuk diingat 5 == idaripada yang alami tetapi rawan kesalahan i == 5.


1
Ausgezeichnet . Demikian pula, seseorang tidak akan menulis tes sebagai i < 17+(36/-3)(bahkan ketika ini adalah konstanta yang digunakan di tempat lain; maka Anda harus menuliskan nama mereka untuk kejelasan!).
usr2564301

6

Menggunakan perbandingan relasional dalam kasus seperti itu lebih merupakan kebiasaan yang populer daripada yang lain. Ini mendapatkan popularitasnya kembali pada masa ketika pertimbangan konseptual seperti kategori iterator dan perbandingan mereka tidak dianggap prioritas tinggi.

Saya akan mengatakan bahwa orang harus lebih suka menggunakan perbandingan kesetaraan daripada perbandingan relasional bila memungkinkan, karena perbandingan kesetaraan memaksakan persyaratan yang lebih sedikit pada nilai yang dibandingkan. Menjadi EqualityComparable adalah persyaratan yang lebih rendah daripada menjadi LessThanComparable .

Contoh lain yang menunjukkan penerapan perbandingan kesetaraan yang lebih luas dalam konteks semacam itu adalah teka-teki populer dengan penerapan unsignediterasi hingga 0. Itu bisa dilakukan sebagai

for (unsigned i = 42; i != -1; --i)
  ...

Perhatikan bahwa hal di atas sama-sama berlaku untuk iterasi yang ditandatangani dan tidak ditandatangani, sementara versi relasional rusak dengan tipe yang tidak ditandatangani.


2

Selain contoh-contoh, di mana variabel loop akan (tidak disengaja) berubah di dalam tubuh, ada reasionasi lain untuk menggunakan operator yang lebih kecil dari atau lebih besar:

  • Negasi membuat kode lebih sulit untuk dipahami
  • <atau >hanya satu arang, tetapi !=dua

4
Peluru kedua paling banter adalah alasan yang sembrono. Kode harus benar dan jelas. Kompak jauh lebih tidak penting.
Jonathan Leffler

@JonathanLeffler Nah, dalam TDD REPL, karakter tambahan itu satu nano-detik ekstra untuk penguraian, dan dikali satu miliar iterasi untuk menemukan bug yang disebabkan oleh tulisan 5 != $i, yang hanya menghabiskan satu detik dalam hidup saya. Uh ... kekek
uskup

1

Selain berbagai orang yang telah menyebutkan bahwa ia mengurangi risiko, itu juga mengurangi jumlah kelebihan fungsi yang diperlukan untuk berinteraksi dengan berbagai komponen perpustakaan standar. Sebagai contoh, jika Anda ingin jenis Anda dapat disimpan dalam std::set, atau digunakan sebagai kunci untuk std::map, atau digunakan dengan beberapa algoritma pencarian dan pengurutan, perpustakaan standar biasanya digunakan std::lessuntuk membandingkan objek karena kebanyakan algoritma hanya membutuhkan urutan lemah yang ketat . Dengan demikian, menjadi kebiasaan yang baik untuk menggunakan <perbandingan alih-alih !=perbandingan (di mana masuk akal, tentu saja).


1
Anda mungkin benar tentang jumlah kelebihan beban, tetapi ketika mempertimbangkan persyaratan pada objek, maka untuk hampir semua objek, seseorang dapat mendefinisikan !=operator, tetapi tidak selalu mungkin untuk menentukan urutan lemah yang ketat. Dalam hal ini !=akan lebih baik, karena menempatkan persyaratan lebih sedikit pada jenisnya. Namun, saya masih tetap dengan <.
idclev 463035818

0

Tidak ada masalah dari perspektif sintaksis, tetapi logika di balik ekspresi 5!=iitu tidak sehat.

Menurut pendapat saya, menggunakan != untuk mengatur batas-batas loop for tidak logis karena loop for meningkatkan atau mengurangi indeks iterasi, jadi mengatur loop untuk beralih sampai indeks iterasi menjadi di luar batas ( !=untuk sesuatu) bukan implementasi yang tepat.

Ini akan bekerja, tetapi rentan terhadap perilaku sejak penanganan data batas hilang ketika menggunakan !=untuk masalah tambahan (yang berarti bahwa Anda tahu dari awal jika penambahan atau decrements), itu sebabnya bukan !=yang <>>==>digunakan.


2
Logikanya baik-baik saja. Ketika iadalah 5pintu keluar lingkaran. Apakah Anda bermaksud mengatakan sesuatu yang lain?
Dan Getz

1
Jika data tidak dapat ditransfer dengan benar karena panas, electro.magnetic memengaruhi kode Anda berjalan selamanya. Jika Anda melakukan ini pada workstation atau server biasa dengan RAM ECC tidak ada masalah (baik logis, teknis maupun fisik)
Markus
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.