¿Las sentencias switch deben contener siempre una cláusula por defecto?


En una de mis primeras revisiones de código (hace un tiempo), me dijeron que es una buena práctica incluir una cláusula predeterminada en todas las instrucciones de switch. Recientemente recordé este consejo, pero no puedo recordar cuál era la justificación. Me suena bastante raro ahora.

  1. ¿Hay una razón sensata para incluir siempre una declaración por defecto?

  2. ¿Depende este idioma? No recuerdo qué idioma estaba usando en ese momento-tal vez esto se aplica a algunos idiomas y a otros no?

Author: tttppp, 2011-01-10

19 answers

Los casos de conmutación deberían casi tener siempre un caso default.

Razones para usar un default

1.To 'catch' un valor inesperado

switch(type)
{
    case 1:
        //something
    case 2:
        //something else
    default:
        // unknown type! based on the language,
        // there should probably be some error-handling
        // here, maybe an exception
}

2. Para manejar acciones 'predeterminadas', donde los casos son para un comportamiento especial.

Esto se ve mucho en programas basados en menús y scripts de shell bash. También puede ver esto cuando una variable se declara fuera del switch-case pero no se inicializa, y cada caso la inicializa a algo diferente. Aquí el valor predeterminado necesita inicializarlo también para que el código de la línea que accede a la variable no genere un error.

3. Para mostrarle a alguien que está leyendo tu código que has cubierto ese caso.

variable = (variable == "value") ? 1 : 2;
switch(variable)
{
    case 1:
        // something
    case 2:
        // something else
    default:
        // will NOT execute because of the line preceding the switch.
}

Este fue un ejemplo demasiado simplificado, pero el punto es que alguien que lee el código no debería preguntarse por qué variable no puede ser otra cosa que 1 o 2.


El único caso que se me ocurre para NO usar default es cuando el interruptor está comprobando algo donde es bastante obvio que cualquier otra alternativa puede ser felizmente ignorada

switch(keystroke)
{
    case 'w':
        // move up
    case 'a':
        // move left
    case 's':
        // move down
    case 'd':
        // move right
    // no default really required here
}
 218
Author: Vanwaril,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-09 04:06:15

Siempre usaría una cláusula predeterminada, sin importar en qué idioma esté trabajando.

Las cosas pueden salir mal y de hecho lo hacen. Los valores no serán lo que esperas, y así sucesivamente.

No querer incluir una cláusula predeterminada implica que está seguro de conocer el conjunto de valores posibles. Si cree que conoce el conjunto de valores posibles, entonces, si el valor está fuera de este conjunto de valores posibles, querrá estar informado de ello, ciertamente es un error.

Esa es la razón por la que siempre debe usar una cláusula predeterminada y lanzar un error, por ejemplo en Java:

switch (myVar) {
   case 1: ......; break;
   case 2: ......; break;
   default: throw new RuntimeException("unreachable");
}

No hay razón para incluir más información que solo la cadena "inalcanzable"; si realmente sucede, tendrá que mirar la fuente y los valores de las variables, etc. de todos modos, y el stacktrace de excepción incluirá ese número de línea, por lo que no es necesario perder el tiempo escribiendo más texto en el mensaje de excepción.

 40
Author: Adrian Smith,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-01-10 17:21:05

No.

Qué pasa si no hay una acción predeterminada, el contexto importa. ¿Qué pasa si sólo te importa actuar en unos pocos valores?

Tomemos el ejemplo de leer pulsaciones de teclas para un juego

switch(a)
{
   case 'w':
     // Move Up
     break;
   case 's':
     // Move Down
     break;
   case 'a':
     // Move Left
     break;
   case 'd':
     // Move Right
     break;
}

Añadiendo:

default: // Do nothing

Es solo una pérdida de tiempo y aumenta la complejidad del código sin ninguna razón.

 36
Author: Jared Kells,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-11 04:45:42

NO tener el caso predeterminado en realidad puede ser beneficioso en algunas situaciones.

Si sus casos de conmutación son valores de enumeración, al no tener un caso predeterminado, puede obtener una advertencia del compilador si le falta algún caso. De esa manera, si se agregan nuevos valores de enumeración en el futuro y se olvida de agregar casos para estos valores en el conmutador, puede averiguar sobre el problema en tiempo de compilación. Aún debe asegurarse de que el código tome las medidas adecuadas para los valores no controlados, en caso de que un valor no válido fue lanzado al tipo enum. Por lo tanto, esto puede funcionar mejor para casos simples en los que puede regresar dentro del caso enum en lugar de romper.

enum SomeEnum
{
    ENUM_1,
    ENUM_2,
    // More ENUM values may be added in future
};

int foo(SomeEnum value)
{
    switch (value)
    {
    case ENUM_1:
        return 1;
    case ENUM_2:
        return 2;
    }
    // handle invalid values here
    return 0;
 }
 33
Author: Harlan Kassler,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-06-19 18:10:25

En mi empresa, escribimos software para el mercado de Aviónica y Defensa, y siempre incluimos una instrucción predeterminada, porque TODOS los casos en una instrucción switch deben manejarse explícitamente (incluso si es solo un comentario que dice 'No hacer nada'). No podemos permitirnos que el software se comporte mal o simplemente se caiga en valores inesperados (o incluso en lo que creemos imposible).

Se puede discutir que un caso predeterminado no siempre es necesario, pero al requerirlo siempre, se comprueba fácilmente por nuestro código analizador.

 13
Author: Kurt Pattyn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-10 14:48:08

¿Debería una sentencia "switch" incluir siempre una cláusula por defecto? No. Debería normalmente incluir un valor predeterminado.

Incluir una cláusula predeterminada solo tiene sentido si hay algo que hacer, como afirmar una condición de error o proporcionar un comportamiento predeterminado. Incluir un "just because" es una programación de culto a la carga y no proporciona ningún valor. Es el equivalente de " cambiar "de decir que todas las declaraciones" if "deben incluir un"else".

Aquí hay un ejemplo trivial de donde no tiene sentido:

void PrintSign(int i)
{
    switch (Math.Sign(i))
    {
    case 1:
        Console.Write("positive ");
        break;
    case -1:
        Console.Write("negative ");
        break;
    default: // useless
    }
    Console.Write("integer");
}

Esto es el equivalente de:

void PrintSign(int i)
{
    int sgn = Math.Sign(i);
    if (sgn == 1)
        Console.Write("positive ");
    else if (sgn == -1)
        Console.Write("negative ");
    else // also useless
    {
    }
    Console.Write("integer");
}
 11
Author: Gabe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-01-10 19:26:49

Por lo que veo la respuesta es 'default' es opcional, decir que un switch siempre debe contener un default es como decir que cada 'if-elseif' debe contener un 'else'. Si hay una lógica que se debe hacer por defecto, entonces la instrucción' default ' debería estar allí, pero de lo contrario el código podría continuar ejecutándose sin hacer nada.

 6
Author: Gershon Herczeg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-09-28 19:07:00

Diría que depende del idioma, pero en C si estás cambiando un tipo de enumeración y manejas todos los valores posibles, probablemente sea mejor NO incluir un caso predeterminado. De esa manera, si agrega una etiqueta de enumeración adicional más tarde y se olvida de agregarla al conmutador, un compilador competente le dará una advertencia sobre el caso que falta.

 5
Author: Chris Dodd,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-01-10 17:30:40

Tener una cláusula por defecto cuando no es realmente necesaria es Programación defensiva Esto generalmente conduce a un código que es demasiado complejo debido al exceso de código de manejo de errores. Este código de detección y manejo de errores daña la legibilidad del código, hace que el mantenimiento sea más difícil y, finalmente, conduce a más errores de los que resuelve.

Así que creo que si no se debe alcanzar el valor predeterminado, no tiene que agregarlo.

Tenga en cuenta que "no debe ser alcanzado" significa que si alcanzado es un error en el software-es necesario probar los valores que pueden contener valores no deseados debido a la entrada del usuario,etc.

 5
Author: Ophir Yoktan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-10-24 18:00:15

Si sabe que la instrucción switch solo tendrá un conjunto definido estricto de etiquetas o valores, simplemente haga esto para cubrir las bases, de esa manera siempre obtendrá un resultado válido.. Simplemente coloque el valor predeterminado sobre la etiqueta que programáticamente / lógicamente sería el mejor manejador para otros valores.

switch(ResponseValue)
{
    default:
    case No:
        return false;
    case Yes;
        return true;
}
 4
Author: deegee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-19 01:37:32

Al menos no es obligatorio en Java. De acuerdo con JLS, dice que atmost un caso predeterminado puede estar presente. Lo que significa que ningún caso predeterminado es aceptable . A veces también depende del contexto en el que esté utilizando la instrucción switch. Por ejemplo, en Java, el siguiente bloque de conmutación no requiere el caso predeterminado

private static void switch1(String name) {
    switch (name) {
    case "Monday":
        System.out.println("Monday");
        break;
    case "Tuesday":
        System.out.println("Tuesday");
        break;
    }
}

Pero en el siguiente método que espera devolver una cadena, el caso predeterminado es útil para evitar errores de compilación

    private static String switch2(String name) {
    switch (name) {
    case "Monday":
        System.out.println("Monday");
        return name;

    case "Tuesday":
        System.out.println("Tuesday");
        return name;

    default:
        return name;
    }
}

Aunque puedes evitar la compilación error para el método anterior sin tener mayúsculas y minúsculas por defecto al tener una sentencia return al final, pero proporcionar mayúsculas y minúsculas por defecto lo hace más legible.

 3
Author: Shiva Kumar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-11-14 13:44:42

Debe tener un valor predeterminado para capturar los valores no esperados que entran.

Sin embargo, no estoy de acuerdo con Adrian Smith que su mensaje de error por defecto debe ser algo totalmente sin sentido. Puede haber un caso no manejado que no hayas visto (que es el punto) que tu usuario terminará viendo y un mensaje como "inalcanzable" es completamente inútil y no ayuda a nadie en esa situación.

Por ejemplo, ¿cuántas veces has tenido un BSOD completamente sin sentido? O una excepción fatal @ 0x352FBB3C32342?

 2
Author: John Hunt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-11 04:21:57

Es una "convención" de codificación opcional. Dependiendo del uso es si es necesario o no. Personalmente creo que si no lo necesitas no debería estar ahí. ¿Por qué incluir algo que no será utilizado o alcanzado por el usuario?

Si las posibilidades de caso son limitadas (es decir, un booleano), entonces la cláusula por defecto es redundante!

 2
Author: Danny Mahoney,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-05-28 12:13:32

Si no hay un caso predeterminado en una instrucción switch, el comportamiento puede ser impredecible si ese caso surge en algún momento, que no era predecible en la etapa de desarrollo. Es una buena práctica incluir un caso default.

switch ( x ){
  case 0 : { - - - -}
  case 1 : { - - - -}
}

/* What happens if case 2 arises and there is a pointer
* initialization to be made in the cases . In such a case ,
* we can end up with a NULL dereference */

Tal práctica puede resultar en un error como NULL eliminar, pérdida de memoria así como otros tipos de errores graves.

Por ejemplo, asumimos que cada condición inicializa un puntero. Pero si default caso es supone surgir y si no inicializamos en este caso, entonces hay todas las posibilidades de aterrizaje con una excepción de puntero nulo. Por lo tanto, se sugiere utilizar una instrucción default case, a pesar de que puede ser trivial.

 2
Author: Nik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-29 15:52:36

Porque MISRA C lo dice:

El requisito para una cláusula final por defecto es la programación defensiva. Esta cláusula deberá adoptar las medidas adecuadas o contener un comentario adecuado sobre las razones por las que no se adopta ninguna medida.

Dicho esto, recomiendo no seguir MISRA C en esto, para la mayoría del software:

  • A esta guía de estilo de programación defensiva no le importa que solo algunos valores puedan ser válidos-si la variable es físicamente capaz de tomar un valor, incluso si eso sería un error, se supone que lo manejes. La mayoría del software debería preferir imprimir un seguimiento de pila en lugar de" manejar " errores (como lo menciona Ophir Yoktan).
  • Los switches Enum, en particular, no deberían tener ninguna cláusula por defecto (como dijo Harlan Kassler). Y, como Harlan también demuestra eminentemente, el manejo de valores no válidos se puede hacer fuera del switch, un punto que faltaba en la discusión de Misra.
 2
Author: user2394284,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-05 21:33:40

Depende de cómo funciona el switch en un idioma en particular, sin embargo, en la mayoría de los idiomas cuando no se coincide con ningún caso, la ejecución cae a través de la instrucción switch sin previo aviso. Imagine que esperaba algún conjunto de valores y los manejó en switch, sin embargo, obtiene otro valor en la entrada. No pasa nada y no sabes que no pasó nada. Si usted cogió el caso por defecto, usted sabría que había algo mal.

 1
Author: Gabriel Ščerbák,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-01-10 17:19:14

Si el valor del switch (switch(variable)) no puede alcanzar el caso predeterminado, entonces el caso predeterminado no es necesario. Incluso si mantenemos el caso predeterminado, no se ejecuta en absoluto. Es un código muerto.

 1
Author: shiju,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-01-08 15:04:23

El caso predeterminado puede no ser necesario en el conmutador utilizado por enum. cuando switch contiene todo el valor, el caso predeterminado nunca se ejecutará. Así que en este caso, no es necesario.

 1
Author: iOkay,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-20 07:04:32

¿Las sentencias switch deben contener siempre una cláusula por defecto ? No puede existir ningún caso de interruptor sin el caso predeterminado, en el caso de interruptor el caso predeterminado activará el valor del interruptor switch(x) en este caso x cuando no coincida con ningún otro valor de caso.

 1
Author: Nisal Edu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-01 19:58:15