Frage Switch Statement Fallthrough ... sollte es erlaubt sein? [geschlossen]


Solange ich mich erinnern kann, habe ich die Verwendung von switch statement fallthrough vermieden. Eigentlich kann ich mich nicht daran erinnern, dass es jemals in mein Bewusstsein gekommen ist als eine mögliche Art, Dinge zu tun, da es mir schon früh in den Kopf gedrillt wurde, dass es nichts weiter als ein Fehler in der switch-Anweisung war. Heute bin ich jedoch über einen Code gestolpert, der es per Design verwendet, was mich sofort dazu gebracht hat, mich darüber zu wundern, was jeder in der Community über den Fall von Switch-Anweisungen denkt.

Ist es etwas, das eine Programmiersprache explizit nicht erlauben sollte (wie C #, obwohl es eine Workaround bietet) oder ist es eine Eigenschaft jeder Sprache, die stark genug ist, um in den Händen des Programmierers zu bleiben?

Bearbeiten: Ich war nicht spezifisch genug, was ich mit Fallthrough meinte. Ich benutze diesen Typ sehr:

    switch(m_loadAnimSubCt){
        case 0: 
        case 1: 
            // Do something
            break;
        case 2:
        case 3:
        case 4:
            // Do something
            break;
   }

Ich mache mir jedoch Sorgen über so etwas.

   switch(m_loadAnimSubCt){
        case 0: 
        case 1: 
            // Do something but fall through to the other cases 
            // after doing it.
        case 2:
        case 3:
        case 4:
            // Do something else.
            break;
   }

Auf diese Weise wird, wenn der Fall 0 ist, alles in der switch-Anweisung ausgeführt. Ich habe das durch Design gesehen und ich weiß einfach nicht, ob ich zustimme, dass Schalteranweisungen auf diese Weise verwendet werden sollten. Ich denke das erste Codebeispiel ist sehr nützlich und sicher. Die zweite scheint irgendwie gefährlich.


85
2017-10-09 18:11


Ursprung


Antworten:


Es kann davon abhängen, was Sie Fall für Fall betrachten. Mir geht es mit so etwas gut:

switch (value)
{
  case 0:
    result = ZERO_DIGIT;
    break;

  case 1:
  case 3:
  case 5:
  case 7:
  case 9:
     result = ODD_DIGIT;
     break;

  case 2:
  case 4:
  case 6:
  case 8:
     result = EVEN_DIGIT;
     break;
}

Aber wenn Sie ein Case-Label gefolgt von einem Code haben, der auf ein anderes Case-Label fällt, würde ich das immer als böse betrachten. Vielleicht wäre es besser, den gemeinsamen Code in eine Funktion zu verschieben und von beiden Orten aus anzurufen.

Und bitte beachte, dass ich das benutze C ++ - FAQ Definition von "böse"


69
2017-10-09 18:18



Es ist ein zweischneidiges Schwert. Manchmal sehr nützlich, oft gefährlich.

Wann ist es gut? Wenn Sie 10 Fälle wollen, werden alle auf die gleiche Weise bearbeitet ...

switch (c) {
  case 1:
  case 2:
            ... do some of the work ...
            /* FALLTHROUGH */
  case 17:
            ... do something ...
            break;
  case 5:
  case 43:
            ... do something else ...
            break;
}

Die eine Regel, die ich mag, ist, dass, wenn Sie etwas Phantasie machen, wo Sie die Pause ausschließen, Sie einen klaren Kommentar / * FALLTHROUGH * / benötigen, um anzuzeigen, dass dies Ihre Absicht war.


44
2017-10-09 18:17



Fallthrough ist wirklich eine praktische Sache, je nachdem, was Sie tun. Betrachten Sie diese übersichtliche und verständliche Art, Optionen zu arrangieren:

switch ($someoption) {
  case 'a':
  case 'b':
  case 'c':
    // do something
    break;
  case 'd':
  case 'e':
    // do something else
    break;
}

Stellen Sie sich vor, Sie machen das mit if / else. Es wäre ein Durcheinander.


18
2017-10-09 18:14



Hast du von ... gehört Duffs Gerät? Dies ist ein großartiges Beispiel für die Verwendung von Switch-Fallout.

Es ist eine Funktion, die verwendet werden kann und wie fast alle Sprachfunktionen missbraucht werden kann.


16
2017-10-09 18:16



Es kann einige Male sehr nützlich sein, aber im Allgemeinen ist das Nicht-Durchfallen das gewünschte Verhalten. Fallthrough sollte erlaubt, aber nicht implizit sein.

Ein Beispiel, um alte Versionen einiger Daten zu aktualisieren:

switch (version) {
    case 1:
        // update some stuff
    case 2:
        // update more stuff
    case 3:
        // update even more stuff
    case 4:
        // and so on
}

9
2017-10-09 19:36



Ich würde eine andere Syntax für Fallbacks in Schalter lieben, etwas wie, errr ..

switch(myParam)
{
  case 0 or 1 or 2:
    // do something;
    break;
  case 3 or 4:
    // do something else;
    break;
}

Hinweis: Dies wäre bereits mit enums möglich, wenn Sie alle Fälle auf Ihrer Enumeration mit Flags richtig deklarieren? Klingt auch nicht so schlecht, die Fälle könnten (sollten?) Schon sehr gut Teil eurer Enum sein.

Vielleicht wäre das ein schöner Fall (kein Wortspiel beabsichtigt) für eine fließende Oberfläche mit Erweiterungsmethoden? Etwas wie, errr ...

int value = 10;
value.Switch()
  .Case(() => { /* do something; */ }, new {0, 1, 2})
  .Case(() => { /* do something else */ } new {3, 4})
  .Default(() => { /* do the default case; */ });

Obwohl das wahrscheinlich noch weniger lesbar ist: P


6
2018-02-10 00:02



Wie bei allem: Wenn es mit Sorgfalt verwendet wird, kann es ein elegantes Werkzeug sein.

Ich denke jedoch, die Nachteile mehr als rechtfertigen, es nicht zu benutzen, und schließlich nicht mehr zu erlauben (C #). Zu den Problemen gehören:

  • Es ist leicht, eine Pause zu "vergessen"
  • es ist nicht immer offensichtlich für Code-Betreuer, dass eine ausgelassene Pause absichtlich war

gute Nutzung eines Switch / Case-Fallouts:

switch (x)
{
case 1:
case 2:
case 3:
 do something
 break;
}

BAAAAAD Verwendung eines Switch / Case Fallthrough:

switch (x)
{
case 1:
    some code
case 2:
    some more code
case 3:
    even more code
    break;
}

Dies kann meiner Meinung nach mit if / else ohne Verluste umgeschrieben werden.

Mein letztes Wort: Bleiben Sie weg von Fall-Fall-Etiketten wie im BAD-Beispiel, es sei denn, Sie pflegen Legacy-Code, wo dieser Stil verwendet und gut verstanden wird.


5
2017-10-09 18:17



Mächtig und gefährlich. Das größte Problem bei der Durchsicht ist, dass es nicht explizit ist. Wenn Sie beispielsweise auf häufig bearbeiteten Code stoßen, der einen Schalter mit Durchschlägen enthält, woher wissen Sie, dass das beabsichtigt ist und kein Bug?

Überall, wo ich es verwende, stelle ich sicher, dass es richtig kommentiert ist:

switch($var) {
    case 'first':
        // fall-through
    case 'second':
        i++;
        break;
 }

4
2017-10-09 18:15



Ich mag meine nicht switch Aussagen fallen durch - es ist viel zu fehleranfällig und schwer zu lesen. Die einzige Ausnahme ist, wenn mehrere case Aussagen tun alle genau das gleiche.

Wenn es einen gemeinsamen Code gibt, den mehrere Zweige einer switch-Anweisung verwenden möchten, extrahiere ich diesen in eine separate allgemeine Funktion, die in jedem Zweig aufgerufen werden kann.


2
2017-10-09 18:17



Durchfall wie in Ihrem ersten Beispiel ist eindeutig in Ordnung, ich würde es nicht als echten Durchgriff betrachten.

Das zweite Beispiel ist gefährlich und (wenn nicht ausführlich kommentiert) nicht offensichtlich. Ich bringe meinen Schülern bei, solche Konstrukte nicht zu verwenden, es sei denn, sie halten es für angebracht, einen Kommentarblock zu schreiben, der beschreibt, dass dies ein absichtlicher Fall ist und warum diese Lösung besser ist als die Alternativen. Dies entmutigt den schlampigen Gebrauch, erlaubt es aber dennoch in den Fällen, in denen es zu einem Vorteil genutzt wird.

Das ist mehr oder weniger gleichbedeutend mit dem, was wir in Raumfahrtprojekten getan haben, als jemand gegen den Codierungsstandard verstoßen wollte: Sie mussten eine Dispensation beantragen (und ich wurde aufgefordert, über die Entscheidung zu beraten).


2
2017-09-10 21:07



Fallgedanken sollten nur verwendet werden, wenn sie als Sprungtabelle in einen Codeblock verwendet werden. Wenn es einen Teil des Codes mit einer bedingungslosen Unterbrechung vor weiteren Fällen gibt, sollten alle Fallgruppen auf diese Weise enden. Alles andere ist "böse".


1
2018-02-09 23:07