Penggunaan yang sesuai dari pernyataan switch jatuh-melalui

14

Kapan tepat menggunakan statement switch fall-through (klasik)? Apakah penggunaan seperti itu direkomendasikan dan dianjurkan atau haruskah dihindari dengan cara apa pun?

shabunc
sumber
Tidak semua bahasa mengizinkan fall-through pada pernyataan switch.
Oded
@Oded, diedit, menambahkan kata "klasik". Tidak semua bahasa mengizinkan jatuh, namun saya bersikeras itu klasik)
shabunc
3
Jika Anda berbicara tentang perangkat Duffs , itu satu hal.
Oded
6
@Oded: Itu hal pertama yang dipikirkan kebanyakan orang, tapi itu hampir tidak "tepat." Menurut ini , Duff sendiri mengatakan, "Ini pasti memberikan argumen dalam diskusi apakah beralih harus gagal secara default, tapi saya tidak yakin apakah argumen itu mendukung atau menentangnya."
BlueRaja - Danny Pflughoeft

Jawaban:

15

Inilah contoh di mana itu akan berguna.

public Collection<LogItems> GetAllLogItems(Level level) {
    Collection<LogItems> result = new Collection<LogItems>();
    switch (level) {
        // Note: fall through here is INTENTIONAL
        case All:
        case Info:
             result.Add(GetItemsForLevel(Info));
        case Warning:
             result.Add(GetItemsForLevel(Warning));
        case Error:
             result.Add(GetItemsForLevel(Error));
        case Critical:
             result.Add(GetItemsForLevel(Critical));
        case None:
    }
    return result;
}

Hal semacam ini (di mana satu kasus termasuk yang lain) agak jarang, saya pikir, itulah sebabnya beberapa bahasa yang lebih baru tidak mengizinkan fallover atau memerlukan sintaks khusus untuk itu.

konfigurator
sumber
13
Contoh ini, meskipun menarik, tidak memiliki // INTENTIONAL FALL THROUGH HEREkomentar lengkap yang diperlukan.
Russell Borogove
Sangat mudah untuk menulis kode ini dengan melewati dengan GetItemsForLevel(Info)meminta panggilan GetItemsForLevel(Warning)dan sebagainya.
Caleb
@RussellBorogove: Benar sekali.
konfigurator
@ Caleb: Dalam hal ini, ya. Tetapi bagaimana jika panggilan itu sedikit lebih rumit? Itu bisa menjadi sedikit berbulu, sementara jatuh membuatnya tampak sederhana. Saya harus mencatat bahwa saya sebenarnya tidak mendukung penggunaan fall through - Saya hanya mengatakan itu bisa berguna dalam situasi tertentu.
konfigurator
Bukan contoh terbaik. Ada pemesanan tingkat peringatan. Dengan mendefinisikan pemesanan itu, metode ini mengurangi ke satu baris item pemfilteran kode ketika level item setidaknya sama dengan level yang diinginkan.
kevin cline
8

Saya menggunakannya ketika fungsi tertentu harus diterapkan untuk lebih dari satu nilai. Misalnya, Anda memiliki objek dengan properti bernama operationCode. Jika kode sama dengan 1, 2, 3 atau 4, Anda ingin memulaiOperationX (). Jika 5 atau 6, Anda ingin memulai operasi () dan 7 Anda memulai operasi (). Mengapa ada 7 case lengkap dengan fungsionalitas dan istirahat ketika Anda dapat menggunakan fall-throughs?

Saya pikir itu sepenuhnya valid dalam situasi tertentu, terutama jika itu menghindari 100 pernyataan if-else. =)

Yatrix
sumber
4
Apa yang Anda gambarkan adalah switchdengan beberapa cases yang terkait dengan kode yang sama. Itu berbeda dari kegagalan, di mana eksekusi satu caseberlanjut ke yang berikutnya karena kurangnya a di breakantara mereka.
Blrfl
3
Tidak masalah, kegagalan hanya karena tidak adanya pernyataan istirahat sehingga "jatuh" ke kasus berikutnya.
Yatrix
Saya akan menuliskan kembali skenario dalam jawaban Anda untuk mencerminkan hal itu.
Blrfl
2
@Yatrix: Saya tidak setuju. Adalah jauh berbeda untuk memiliki semua kasus berturut-turut mengeksekusi blok kode yang sama persis daripada menghilangkan istirahat. Salah satunya adalah rutin, yang lain jauh dari itu (ime) - dan potensi aliran kontrol salah baca dan tidak disengaja jauh lebih besar.
quentin-starin
3
@ Ya, itu berbeda, tapi keduanya gagal. Dia bertanya kapan / apakah itu pantas. Saya memberi contoh kapan. Itu tidak dimaksudkan untuk menjadi contoh semua termasuk. Bergantung pada bahasanya, memiliki pernyataan sebelum jatuh mungkin tidak berhasil. Saya tidak berpikir itu akan dengan C # stackoverflow.com/questions/174155/…
Yatrix
8

Saya sudah menggunakannya sesekali, saya pikir itu selalu penggunaan yang tepat - tetapi hanya ketika disertakan dengan komentar yang sesuai.

gbjbaanb
sumber
7

Kasing jatuh baik-baik saja. Saya sering menemukan bahwa enumerasi digunakan di banyak tempat, dan ketika Anda tidak perlu membedakan beberapa kasus, lebih mudah menggunakan logika fall-through.

Misalnya (perhatikan komentar penjelas):

public boolean isAvailable(Server server, HealthStatus health) {
  switch(health) {
    // Equivalent positive cases
    case HEALTHY:
    case UNDER_LOAD:
      return true;

    // Equivalent negative cases
    case FAULT_REPORTED:
    case UNKNOWN:
    case CANNOT_COMMUNICATE:
      return false;

    // Unknown enumeration!
    default:
      LOG.warn("Unknown enumeration " + health);
      return false;
  }
}

Saya menemukan penggunaan semacam ini bisa diterima.

Bringer128
sumber
Perhatikan bahwa ada perbedaan besar antara case X: case Y: doSomething()dan case X: doSomething(); case Y: doAnotherThing(). Dalam yang pertama, niatnya cukup eksplisit, sedangkan yang kedua, kejatuhannya mungkin disengaja atau tidak. Dalam pengalaman saya, contoh pertama tidak pernah memicu peringatan apa pun di kompiler / penganalisa kode, sedangkan yang kedua tidak. Secara pribadi, saya hanya akan menyebut contoh kedua "gagal" - tidak yakin tentang definisi "resmi".
Jens Bannmann
6

Tergantung pada:

  • preferensi pribadi Anda
  • standar pengkodean atasan Anda
  • jumlah risiko yang terlibat

Dua masalah utama yang terkait dengan membiarkan satu kasus jatuh ke yang berikutnya adalah:

  1. Itu membuat kode Anda tergantung pada urutan pernyataan kasus. Itu tidak terjadi jika Anda tidak pernah gagal, dan itu menambah tingkat kerumitan yang sering tidak diinginkan.

  2. Tidak jelas bahwa kode untuk satu kasus menyertakan kode untuk satu atau lebih kasus berikutnya.

Beberapa tempat secara eksplisit melarang jatuh. Jika Anda tidak bekerja di tempat seperti itu, dan jika Anda merasa nyaman dengan latihan itu, dan jika melanggar kode yang dimaksud tidak akan menyebabkan penderitaan nyata, maka itu mungkin bukan hal terburuk di dunia. Namun, jika Anda melakukannya, pastikan untuk meletakkan komentar yang menarik perhatian di dekat untuk memperingatkan mereka yang datang kemudian (termasuk masa depan Anda).

Caleb
sumber
4

Berikut adalah contoh cepat (diakui tidak lengkap (tidak ada penanganan khusus tahun kabisat)) yang membuat hidup saya lebih sederhana:

function get_julian_day (date) {
    int utc_date = date.getUTCDate();
    int utc_month = date.getUTCMonth();

    int julian_day = 0;

    switch (utc_month) {
        case 11: julian_day += 30;
        case 10: julian_day += 31;
        case 9:  julian_day += 30;
        case 8:  julian_day += 31;
        case 7:  julian_day += 31;
        case 6:  julian_day += 30;
        case 5:  julian_day += 31;
        case 4:  julian_day += 30;
        case 3:  julian_day += 31;
        case 2:  julian_day += 28;
        case 1:  julian_day += 31;
        default: break;
    }

    return julian_day + utc_date;
}
AaronDanielson
sumber
5
Meskipun ini agak pintar, waktu yang Anda hemat dari melakukan ini akan jauh lebih berat daripada waktu yang diperlukan orang lain untuk mengetahui apa yang dilakukannya. Juga, Anda bisa mendapatkan kinerja yang lebih baik dengan menghapus aspek fall-through yaitu 31 + 28 + 31 selalu 90. Jika Anda akan melakukan ini, Anda mungkin juga memasukkan totalnya ke dalam case karena hanya ada 11 yang perlu dipertimbangkan.
JimmyJames
Anda benar, contoh saya pasti dibuat-buat :) Saya akan mengatakan, bagaimanapun, lebih mudah untuk menemukan bug tersembunyi ketika jumlah hari dijabarkan seperti ini daripada melakukan pra-komputasi semua hari kumulatif untuk setiap kasus saklar .
AaronDanielson
2
Saya akan memberi Anda itu tetapi melakukan itu dalam deklarasi konstan akan lebih disukai misalnya FEB_START = 31; MAR_START = FEB_START + 28; dll. tidak yakin apa bahasa ini tetapi dalam banyak, itu akan dihitung pada waktu kompilasi. Masalah yang lebih besar di sini adalah bahwa itu agak tumpul. Bukan karena itu ide yang buruk, hanya atipikal. Kecuali ada manfaat yang sangat besar, umumnya lebih baik tetap dengan idiom umum.
JimmyJames
1
Alternatif yang sangat baik, menggunakan konstanta untuk hari mulai pada contoh ini. Bagaimanapun, intinya di sini adalah bahwa jumlah kumulatif adalah penggunaan yang bagus untuk switch-case fall-through. Saya setuju 100% untuk menggunakan idiom umum, tetapi sifat dari pertanyaan ini adalah menjelajah ke fitur yang lebih esoterik di mana idiom umum sulit didapat.
AaronDanielson
3

Jika saya merasa perlu untuk beralih dari satu kasus ke kasus lain (jarang, harus diakui), saya lebih suka untuk menjadi sangat eksplisit dan goto case, tentu saja, yang mengasumsikan bahasa Anda mendukungnya.

Karena jatuh melalui sangat jarang, dan sangat mudah untuk diabaikan saat membaca kode, saya merasa pantas untuk eksplisit - dan goto, bahkan jika itu untuk sebuah kasus, harus menonjol seperti jempol yang sakit.

Ini juga membantu menghindari bug yang mungkin terjadi ketika pernyataan kasus disusun ulang.

quentin-starin
sumber