Usos apropiados de las declaraciones de interrupción fallida

14

¿Cuándo es apropiado usar una declaración de cambio fallido (clásico)? ¿Se recomienda y alienta tal uso o debe evitarse a toda costa?

shabunc
fuente
No todos los idiomas permiten fallos en las declaraciones de cambio.
Oded
@ Palabra "clásica" editada, editada y agregada. No todos los idiomas permiten caer, sin embargo, insisto en que es clásico)
shabunc
3
Si estás hablando del dispositivo de Duffs , eso es una cosa.
Oded
66
@Oded: Eso es lo primero en lo que la mayoría de la gente piensa, pero eso no es "apropiado". De acuerdo con esto , el propio Duff dijo "Esto definitivamente proporciona un argumento en la discusión sobre si el cambio debería fallar por defecto, pero no estoy seguro de si el argumento es a favor o en contra".
BlueRaja - Danny Pflughoeft

Respuestas:

15

Aquí hay un ejemplo donde sería útil.

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

Creo que este tipo de cosas (donde un caso incluye el otro) es bastante raro, por lo que algunos idiomas más nuevos no permiten Falla o requieren una sintaxis especial para ello.

configurador
fuente
13
Este ejemplo, aunque interesante, carece del // INTENTIONAL FALL THROUGH HEREcomentario de mayúsculas requerido .
Russell Borogove
Es tan fácil escribir este código con fallar al GetItemsForLevel(Info)hacer que se invoque la llamada, GetItemsForLevel(Warning)etc.
Caleb
@RussellBorogove: Absolutamente correcto.
configurador
@Caleb: En este caso, sí. Pero, ¿y si las llamadas fueran un poco más complicadas? Podría ponerse un poco peludo, mientras que la caída lo hace parecer simple. Debo señalar que en realidad no estoy a favor de usar Fall-Fall, solo digo que puede ser útil en ciertas situaciones.
configurador
No es el mejor ejemplo. Hay un orden de los niveles de advertencia. Al definir ese orden, este método se reduce a una sola línea de elementos de filtrado de código cuando el nivel del elemento es al menos igual al nivel deseado.
Kevin Cline
8

Los uso cuando se debe aplicar cierta funcionalidad para más de un valor. Por ejemplo, supongamos que tenía un objeto con una propiedad llamada operationCode. Si el código es igual a 1, 2, 3 o 4, desea iniciar OperationX (). Si es 5 o 6, desea iniciar OperaciónY () y 7 inicia OperaciónZ (). ¿Por qué tener 7 casos completos con funcionalidad y pausas cuando puede usar fall-throughs?

Creo que es completamente válido en ciertas situaciones, especialmente si evita 100 declaraciones if-else. =)

Yatrix
fuente
44
Lo que está describiendo es un switchcon múltiples cases vinculados al mismo código. Eso es diferente a un fracaso, donde la ejecución de uno casecontinúa en el siguiente debido a la falta de un breakentre ellos.
Blrfl
3
Realmente no importa, el fracaso es solo la falta de una declaración de ruptura, por lo que "falla" al siguiente caso.
Yatrix
Reformularía el escenario en tu respuesta para reflejar eso.
Blrfl
2
@Yatrix: no estoy de acuerdo. Es muy diferente tener casos consecutivos que ejecuten exactamente el mismo bloque de código que omitir un descanso. Uno es de rutina, el otro está lejos de serlo (ime), y el potencial de lectura errónea y flujo de control no deseado es mucho mayor.
quentin-starin
3
@qes sí, es diferente, pero ambos son fallos. Preguntó cuándo / si sería apropiado. Di un ejemplo de cuándo lo haría. No pretendía ser un ejemplo todo incluido. Dependiendo del idioma, tener declaraciones antes de una caída puede no funcionar. No creo que lo haga con C # stackoverflow.com/questions/174155/…
Yatrix
8

Los he usado ocasionalmente, creo que siempre es el uso apropiado, pero solo cuando se incluye con el comentario apropiado.

gbjbaanb
fuente
7

Los casos de caída están perfectamente bien. A menudo encuentro que una enumeración se usa en muchos lugares, y que cuando no es necesario diferenciar algunos casos, es más fácil usar la lógica de caída.

Por ejemplo (tenga en cuenta los comentarios explicativos):

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

Este tipo de uso me parece perfectamente aceptable.

Bringer128
fuente
Tenga en cuenta que hay una gran diferencia entre case X: case Y: doSomething()y case X: doSomething(); case Y: doAnotherThing(). En el primero, la intención es bastante explícita, mientras que en el segundo, la caída puede ser intencional o no. En mi experiencia, el primer ejemplo nunca activa advertencias en compiladores / analizadores de código, mientras que el segundo sí. Personalmente, solo llamaría al segundo ejemplo "caer", aunque no estoy seguro de una definición "oficial".
Jens Bannmann
6

Depende de:

  • su preferencia personal
  • los estándares de codificación de su empleador
  • la cantidad de riesgo involucrado

Los dos problemas principales asociados con dejar que un caso caiga al siguiente son:

  1. Hace que su código dependa del orden de las declaraciones de casos. Ese no es el caso si nunca se cae, y agrega un grado de complejidad que a menudo no es bienvenido.

  2. No es obvio que el código para un caso incluye el código para uno o más casos posteriores.

Algunos lugares prohíben explícitamente la caída. Si no trabaja en ese lugar, y si se siente cómodo con la práctica, y si descifrar el código en cuestión no causará ningún sufrimiento real, entonces podría no ser lo peor del mundo. Sin embargo, si lo haces, asegúrate de poner un comentario que llame la atención cerca para advertir a los que vengan después (incluido tu futuro).

Caleb
fuente
4

Aquí hay un ejemplo rápido (admitidamente incompleto (sin manejo especial del año bisiesto)) de fallas que simplifican mi vida:

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
fuente
55
Si bien esto es un poco inteligente, el tiempo que ahorre al hacer esto va a ser muy superior al tiempo que le toma a otras personas darse cuenta de lo que esto hace. Además, podría obtener un mejor rendimiento al eliminar el aspecto de caída, es decir, 31 + 28 + 31 siempre es 90. Si va a hacer esto, también podría poner los totales en los casos, ya que solo hay 11 para considerar.
JimmyJames
Tienes razón, mi ejemplo es definitivamente ideado :) Diré, sin embargo, es más fácil detectar un error oculto cuando la cantidad de días se deletrea así en lugar de calcular previamente todos los días acumulativos para cada caso del interruptor .
AaronDanielson
2
Te lo concederé, pero sería preferible hacerlo en una declaración constante, por ejemplo, FEB_START = 31; MAR_START = FEB_START + 28; etc., no estoy seguro de qué idioma es, pero en muchos casos se calcularía en tiempo de compilación. El problema más grande aquí es que es un poco obtuso. No es tanto que sea una mala idea, solo atípica. A menos que haya un gran beneficio, generalmente es mejor seguir con expresiones idiomáticas comunes.
JimmyJames
1
Excelente alternativa, utilizando constantes para los días de inicio en este ejemplo. De todos modos, el punto aquí es que una suma acumulativa es un gran uso para una falla de cambio de mayúsculas y minúsculas. Estoy 100% de acuerdo con el uso de modismos comunes, pero la naturaleza de esta pregunta es aventurarse en las características más esotéricas donde los modismos comunes son difíciles de encontrar.
AaronDanielson el
3

Si siento la necesidad de pasar de un caso a otro (raro, lo admito), prefiero ser muy explícito y goto case, por supuesto, eso supone que su idioma lo respalde.

Debido a que caer es muy poco común y muy fácil de pasar por alto al leer el código, creo que es apropiado ser explícito, y un goto, incluso si es un caso, debería destacarse como un pulgar dolorido.

También ayuda a evitar errores que pueden ocurrir cuando se reordenan las declaraciones de casos.

quentin-starin
fuente