Usi appropriati delle istruzioni switch fall-through


14

Quando è appropriato utilizzare un'istruzione switch fall-through (classica)? Tale utilizzo è raccomandato e incoraggiato o dovrebbe essere evitato a tutti i costi?


Non tutte le lingue consentono il fall-through sulle istruzioni switch.
Oded,

@Oded, modificato, ha aggiunto la parola "classico". Non tutte le lingue permettono di fallire, tuttavia insisto che è classico)
shabunc

3
Se stai parlando del dispositivo di Duff , questa è una cosa.
Oded,

6
@Oded: Questa è la prima cosa a cui la maggior parte della gente pensa, ma non è certo "appropriato". Secondo questo , Duff stesso ha affermato che "Questo fornisce sicuramente un argomento nella discussione se l'interruttore dovrebbe fallire per impostazione predefinita, ma non sono sicuro che l'argomento sia pro o contro".
BlueRaja - Danny Pflughoeft,

Risposte:


15

Ecco un esempio in cui sarebbe utile.

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;
}

Questo genere di cose (in cui un caso include l'altro) è piuttosto raro, penso, ed è per questo che alcuni linguaggi più recenti non consentono il fallover o richiedono una sintassi speciale per questo.


13
In questo esempio, sebbene interessante, manca il // INTENTIONAL FALL THROUGH HEREcommento in maiuscolo richiesto .
Russell Borogove,

È altrettanto facile scrivere questo codice fallendo facendo GetItemsForLevel(Info)invocare la chiamata GetItemsForLevel(Warning)e così via.
Caleb

@RussellBorogove: assolutamente corretto.
configuratore

@Caleb: in questo caso, sì. E se le chiamate fossero state un po 'più complicate? Potrebbe diventare un po 'peloso, mentre cadere attraverso sembra semplice. Dovrei notare che in realtà non sono favorevole all'utilizzo di fall through, sto solo dicendo che può essere utile in determinate situazioni.
configuratore

Non è il miglior esempio. Esiste un ordinamento dei livelli di avviso. Definendo tale ordinamento, questo metodo si riduce a una singola riga di articoli di filtro del codice quando il livello dell'articolo è almeno uguale al livello desiderato.
Kevin Cline,

8

Li uso quando è necessario applicare determinate funzionalità per più di un valore. Ad esempio, supponiamo che tu avessi un oggetto con una proprietà chiamata operationCode. Se il codice è uguale a 1, 2, 3 o 4, si desidera avviare OperazioneX (). Se è 5 o 6, desideri startOperationY () e 7 startOperationZ (). Perché 7 casi completi con funzionalità e interruzioni quando è possibile utilizzare i fall-through?

Penso che sia completamente valido in determinate situazioni, specialmente se evita 100 dichiarazioni if-else. =)


4
Quello che stai descrivendo è a switchcon più cases legate allo stesso codice. È diverso da un fall-through, in cui l'esecuzione di uno casecontinua nel successivo a causa della mancanza di una breaktra di loro.
Blrfl,

3
Non importa, il fall-through è solo la mancanza di una dichiarazione di rottura, quindi "fallisce" nel caso successivo.
Yatrix,

Riscriverei lo scenario nella tua risposta per riflettere ciò.
Blrfl,

2
@Yatrix: non sono d'accordo. È molto diverso avere casi consecutivi che eseguono esattamente lo stesso blocco di codice piuttosto che omettere un'interruzione. Uno è di routine, l'altro lontano da esso (ime) - e il potenziale di lettura errata e flusso di controllo involontario è molto maggiore.
Quentin-starin,

3
@qi sì, è diverso, ma sono entrambi fall-through. Ha chiesto quando / se sarebbe appropriato. Ho dato un esempio di quando sarebbe successo. Non intendeva essere un esempio all-inclusive. A seconda della lingua, avere dichiarazioni prima di un fall-through potrebbe non funzionare. Non credo che lo farà con C # stackoverflow.com/questions/174155/...
Yatrix

8

Li ho usati di tanto in tanto, penso che sia sempre un uso appropriato, ma solo se incluso nel commento appropriato.


7

I casi di caduta sono perfettamente a posto. Trovo spesso che un'enumerazione sia utilizzata in molti luoghi e che quando non è necessario differenziare alcuni casi è più facile usare la logica fall-through.

Ad esempio (notare i commenti esplicativi):

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;
  }
}

Trovo questo tipo di utilizzo perfettamente accettabile.


Nota che c'è una grande differenza tra case X: case Y: doSomething()e case X: doSomething(); case Y: doAnotherThing(). Nel primo, l'intenzione è abbastanza esplicita, mentre nel secondo, la caduta può essere intenzionale o no. Nella mia esperienza, il primo esempio non attiva mai alcun avviso nei compilatori / analizzatori di codice, mentre il secondo lo fa. Personalmente, chiamerei solo il secondo esempio "fall through" - non sono sicuro di una definizione "ufficiale", però.
Jens Bannmann,

6

Dipende da:

  • le tue preferenze personali
  • gli standard di codifica del tuo datore di lavoro
  • la quantità di rischio coinvolto

I due problemi principali associati a far passare un caso al successivo sono:

  1. Rende il tuo codice dipendente dall'ordine delle dichiarazioni del caso. Questo non è il caso se non si fallisce mai, e aggiunge un grado di complessità che spesso non è gradito.

  2. Non è ovvio che il codice per un caso includa il codice per uno o più casi successivi.

Alcuni luoghi proibiscono esplicitamente di cadere. Se non lavori in un posto del genere, e se ti senti a tuo agio con la pratica, e se infrangere il codice in questione non causerà alcuna vera sofferenza, allora potrebbe non essere la cosa peggiore del mondo. Se lo fai, però, assicurati di mettere un commento che catturi l'attenzione nelle vicinanze per avvertire coloro che verranno dopo (incluso il futuro tu).


4

Ecco un esempio rapido (certamente incompleto (nessuna gestione speciale dell'anno bisestile)) di fallimenti che mi semplificano la vita:

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;
}

5
Mentre questo è un po 'intelligente, il tempo che risparmi nel farlo sarà di gran lunga superiore al tempo impiegato da altre persone per capire cosa fa. Inoltre, potresti ottenere prestazioni migliori rimuovendo l'aspetto di fall-through, ovvero 31 + 28 + 31 è sempre 90. Se hai intenzione di farlo, potresti anche semplicemente inserire i totali nei casi poiché ci sono solo 11 da considerare.
JimmyJames,

Hai ragione, il mio esempio è decisamente elaborato :) Dirò, tuttavia, è più facile individuare un bug nascosto quando il numero di giorni è spiegato in questo modo invece di pre-calcolare tutti i giorni cumulativi per ogni caso del passaggio .
AaronDanielson,

2
Ti garantirò che, ma farlo in una dichiarazione costante sarebbe preferibile, ad esempio FEB_START = 31; MAR_START = FEB_START + 28; ecc. non sono sicuro di che lingua sia, ma in molti sarebbe calcolato al momento della compilazione. Il problema più grande qui è che è un po 'ottuso. Non tanto che è una cattiva idea, solo atipica. A meno che non ci sia un grande vantaggio, è generalmente meglio attenersi ai modi di dire comuni.
JimmyJames,

1
Ottima alternativa, usando costanti per i giorni di inizio in questo esempio. In ogni caso, il punto qui è che una somma cumulativa è di grande utilità per un caso di fall-through. Sono d'accordo al 100% sull'uso di idiomi comuni, ma la natura di questa domanda si sta avventurando nelle caratteristiche più esoteriche in cui è difficile trovare idiomi comuni.
AaronDanielson,

3

Se sento la necessità di passare da un caso all'altro (raro, devo ammettere), preferisco essere molto esplicito e goto case , naturalmente, ciò presuppone che la tua lingua lo supporti.

Poiché cadere attraverso è così insolito e molto facile da trascurare durante la lettura del codice, ritengo sia opportuno essere espliciti - e un goto, anche se è un caso, dovrebbe emergere come un pollice dolente.

Aiuta anche a evitare bug che possono verificarsi quando le istruzioni del caso vengono riordinate.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.