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 declaraciones de cambio. Recientemente recordé este consejo, pero no recuerdo cuál era la justificación. Me suena bastante extraño ahora.
¿Hay alguna razón sensata para incluir siempre una declaración predeterminada?
¿Es este idioma dependiente? No recuerdo qué idioma estaba usando en ese momento, ¿tal vez esto se aplica a algunos idiomas y no a otros?
default
switch-statement
tttppp
fuente
fuente
Respuestas:
Los casos de cambio casi siempre deberían tener un
default
caso.Razones para usar un
default
1.Para 'atrapar' un valor inesperado
2. Para manejar acciones 'predeterminadas', donde los casos son de comportamiento especial.
Usted ve MUCHO en los programas controlados por menús y los scripts de shell bash. También puede ver esto cuando una variable se declara fuera del caso de cambio pero no se inicializa, y cada caso la inicializa en algo diferente. Aquí, el valor predeterminado también debe inicializarse para que el código de línea que accede a la variable no genere un error.
3. Para mostrarle a alguien que lee su código que ha cubierto ese caso.
Este fue un ejemplo demasiado simplificado, pero el punto es que alguien que lea 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 que NO debo usar
default
es cuando el interruptor está verificando algo donde es bastante obvio que cualquier otra alternativa puede ignorarse felizmentefuente
enum MyEnum { FOO = 0, BAR = 1 }; MyEnum value = (MyEnum)2;
hace unaMyEnum
instancia válida que no es igual aFOO
oBAR
. Si cualquiera de estos problemas causara un error en su proyecto, un caso predeterminado lo ayudará a encontrar el error muy rápidamente, ¡a menudo sin necesidad de depurador!No.
¿Qué pasa si no hay una acción predeterminada? El contexto importa. ¿Qué pasa si solo te importa actuar con unos pocos valores?
Tome el ejemplo de leer las pulsaciones de teclas para un juego
Agregando:
Es solo una pérdida de tiempo y aumenta la complejidad del código sin ningún motivo.
fuente
// do nothing
comentario simple, queda claro que está 'bien' si no se cubren todos los casos, a diferencia de otras declaraciones de cambio donde esto sería 'no está bien'.NO tener el caso predeterminado puede ser realmente beneficioso en algunas situaciones.
Si sus casos de cambio son valores de enumeración, al no tener un caso predeterminado, puede obtener una advertencia del compilador si falta algún caso. De esa manera, si se agregan nuevos valores de enumeración en el futuro y olvida agregar casos para estos valores en el conmutador, puede averiguar el problema en el momento de la compilación. Todavía debe asegurarse de que el código tome las medidas adecuadas para los valores no controlados, en caso de que se haya emitido un valor no válido al tipo de enumeración. Por lo tanto, esto puede funcionar mejor para casos simples en los que puede regresar dentro del caso enum en lugar de romper.
fuente
Siempre usaría una cláusula predeterminada, sin importar en qué idioma esté trabajando.
Las cosas pueden y salen mal. Los valores no serán lo que espera, y así sucesivamente.
No querer incluir una cláusula predeterminada implica que está seguro de conocer el conjunto de valores posibles. Si crees que conoces el conjunto de valores posibles, entonces, si el valor está fuera de este conjunto de valores posibles, querrás que te informen, es ciertamente un error.
Esa es la razón por la que siempre debe usar una cláusula predeterminada y arrojar un error, por ejemplo en Java:
No hay razón para incluir más información que solo la cadena "inalcanzable"; si realmente sucede, tendrá que mirar el origen 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 necesita perder el tiempo escribiendo más texto en el mensaje de excepción.
fuente
throw new RuntimeException("myVar invalid " + myVar);
ya que eso podría darle suficiente información para descubrir y corregir el error sin tener que usar un depurador e inspeccionar variables, lo que puede ser difícil si este es un problema que rara vez se produce y que es difícil de reproducir.default:
. Pero más a menudo que no, uno deja de lado un valor predeterminado porque uno piensamyVar
que nunca puede tener ningún valor distinto de los enumerados; Sin embargo, no puedo contar la cantidad de veces que me he sorprendido en la vida real cuando la variable ha tenido un valor diferente a los valores que "posiblemente" podría tener. En esos casos, he agradecido la excepción que me hizo ver eso de inmediato, en lugar de causar algún otro error más tarde (más difícil de depurar) o una respuesta incorrecta (podría pasarse por alto en las pruebas).AssertionError
lugar deRuntimeException
, ya que esta situación es muy similar a una afirmación que indica quemyVar
es uno de los valores manejados. También la posibilidad de que alguien atrape y se trague el error es menor.En mi empresa, escribimos software para el mercado de aviónica y defensa, y siempre incluimos una declaración por defecto, porque TODOS los casos en una declaración de cambio 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 estrelle con valores inesperados (o incluso lo que creemos imposible).
Se puede discutir que un caso predeterminado no siempre es necesario, pero al requerirlo siempre, nuestros analizadores de código lo verifican fácilmente.
fuente
¿Debería una declaración de "cambio" incluir siempre una cláusula predeterminada? No. Por lo general, debe incluir un valor predeterminado.
Incluir una cláusula predeterminada solo tiene sentido si tiene algo que hacer, como afirmar una condición de error o proporcionar un comportamiento predeterminado. Incluyendo uno "solo porque" es la programación de culto de carga y no proporciona ningún valor. Es el "cambio" equivalente a decir que todas las declaraciones "if" deben incluir un "else".
Aquí hay un ejemplo trivial de dónde no tiene sentido:
Este es el equivalente de:
fuente
default:
en esos casos codifica sus suposiciones. Por ejemplo, ¿está bien cuándosgn==0
imprimirinteger
(ni positivo ni negativo) o es un error? Para mí leer ese código, es difícil de decir. Supongo que no querría escribirzero
en ese casointeger
, y que el programador asumió quesgn
solo puede ser -1 o +1. Si ese fuera el caso, tener eldefault:
permitiría al programador detectar el error de suposición antes y cambiar el código.Por lo que veo, la respuesta es 'predeterminado' es opcional, decir que un interruptor siempre debe contener un valor predeterminado es como decir que cada 'if-elseif' debe contener un 'else'. Si hay una lógica que hacer por defecto, entonces la declaración 'default' debería estar allí, pero de lo contrario el código podría continuar ejecutándose sin hacer nada.
fuente
Tener una cláusula predeterminada cuando realmente no es necesaria es una programación defensiva. Esto generalmente conduce a un código que es demasiado complejo debido a un código de manejo de errores excesivo. Este código de detección y manejo de errores daña la legibilidad del código, dificulta el mantenimiento y eventualmente genera más errores de los que resuelve.
Así que creo que si no se alcanza el valor predeterminado, no tiene que agregarlo.
Tenga en cuenta que "no se debe alcanzar" significa que si se alcanza es un error en el software, debe probar los valores que pueden contener valores no deseados debido a la entrada del usuario, etc.
fuente
Diría que depende del lenguaje, pero en C si está cambiando un tipo de enumeración y maneja 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 olvida agregarla al conmutador, un compilador competente le dará una advertencia sobre el caso perdido.
fuente
gcc -Wall
(una especie del mínimo común denominador de compiladores competentes) ofrece advertencias sobre enumeraciones no controladas en las declaraciones de cambio.Si sabe que la declaración de cambio solo tendrá un conjunto estrictamente definido 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 sería programática / lógicamente ser el mejor manejador para otros valores.
fuente
default
Aún se requiere el colon después ? ¿O hacer esto permite una sintaxis especial que le permitió omitirla?Al menos no es obligatorio en Java. Según JLS, dice que casi un caso predeterminado puede estar presente. Lo que significa que no se acepta ningún caso predeterminado. A veces también depende del contexto en el que está utilizando la instrucción switch. Por ejemplo, en Java, el siguiente bloque de interruptores no requiere un caso predeterminado
Pero en el siguiente método que espera devolver una Cadena, el caso predeterminado es útil para evitar errores de compilación
aunque puede evitar el error de compilación para el método anterior sin tener un caso predeterminado con solo tener una declaración de devolución al final, pero proporcionar un caso predeterminado lo hace más legible.
fuente
Algunas pautas (obsoletas) lo dicen, como MISRA C :
Ese consejo está desactualizado porque no se basa en criterios actualmente relevantes. La omisión deslumbrante es lo que dijo Harlan Kassler:
Dejar de lado el caso predeterminado permite al compilador opcionalmente advertir o fallar cuando ve un caso no manejado. La verificabilidad estática es, después de todo, mejor que cualquier verificación dinámica y, por lo tanto, no es un sacrificio digno para cuando también se necesita la verificación dinámica.
Como Harlan también demostró, el equivalente funcional de un caso predeterminado puede recrearse después del cambio. Lo cual es trivial cuando cada caso es un retorno temprano.
La necesidad típica de una verificación dinámica es el manejo de entradas, en un sentido amplio. Si un valor proviene de fuera del control del programa, no se puede confiar en él.
Aquí también es donde Misra toma el punto de vista de la programación defensiva extrema, por lo que siempre que un valor no válido sea físicamente representable, debe verificarse, sin importar si el programa es demostrablemente correcto. Lo cual tiene sentido si el software necesita ser lo más confiable posible en presencia de errores de hardware. Pero como dijo Ophir Yoktan, es mejor que la mayoría de los programas no "manejen" los errores. La última práctica a veces se llama programación ofensiva .
fuente
Debería tener un valor predeterminado para detectar los valores no esperados.
Sin embargo, no estoy de acuerdo con Adrian Smith en que su mensaje de error por defecto debería ser algo totalmente sin sentido. Puede haber un caso no manejado que no previó (lo cual es un punto) que su usuario terminará viendo y un mensaje como "inalcanzable" no tiene ningún sentido y no ayuda a nadie en esa situación.
Caso en cuestión, ¿cuántas veces has tenido un BSOD completamente sin sentido? ¿O una excepción fatal @ 0x352FBB3C32342?
fuente
Si el valor del interruptor ( interruptor (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.
fuente
Es una 'convención' de codificación opcional. Dependiendo del uso es si es necesario o no. Personalmente, creo que si no lo necesita, no debería estar allí. ¿Por qué incluir algo que el usuario no utilizará o alcanzará?
Si las posibilidades del caso son limitadas (es decir, un booleano), ¡la cláusula predeterminada es redundante !
fuente
Si no hay un caso predeterminado en una
switch
declaración, el comportamiento puede ser impredecible si ese caso surge en algún momento, lo que no era predecible en la etapa de desarrollo. Es una buena práctica incluir undefault
caso.Tal práctica puede provocar un error como la anulación de la referencia NULL , pérdida de memoria y otros tipos de errores graves .
Por ejemplo, suponemos que cada condición inicializa un puntero. Pero si
default
se supone que surge un caso y si no lo inicializamos en este caso, entonces hay todas las posibilidades de aterrizar con una excepción de puntero nulo. Por lo tanto, se sugiere utilizar unadefault
declaración de caso, aunque pueda ser trivial.fuente
El caso predeterminado puede no ser necesario en el conmutador utilizado por enum. cuando el interruptor contenía todo el valor, el caso predeterminado nunca se ejecutará. Entonces, en este caso, no es necesario.
fuente
Depende de cómo funciona el conmutador en un idioma en particular, sin embargo, en la mayoría de los idiomas, cuando ningún caso coincide, la ejecución cae a través de la declaración del conmutador sin previo aviso. Imagine que esperaba un conjunto de valores y los manejó en el interruptor, sin embargo, obtiene otro valor en la entrada. No pasa nada y no sabes que no pasó nada. Si detecta el caso por defecto, sabría que algo anda mal.
fuente
No estoy de acuerdo con la respuesta más votada de Vanwaril arriba.
Cualquier código agrega complejidad. También se deben hacer pruebas y documentación para ello. Por lo tanto, siempre es bueno si puede programar con menos código. Mi opinión es que uso una cláusula predeterminada para declaraciones de cambio no exhaustivas, mientras que no uso una cláusula predeterminada para declaraciones de cambio exhaustivas. Para estar seguro de haberlo hecho bien, uso una herramienta de análisis de código estático. Así que vamos a los detalles:
Sentencias de cambio no exhaustivo: siempre deben tener un valor predeterminado. Como su nombre indica, esas son declaraciones que no cubren todos los valores posibles. Esto también podría no ser posible, por ejemplo, una declaración de cambio en un valor entero o en una cadena. Aquí me gustaría usar el ejemplo de Vanwaril (Cabe mencionar que creo que él usó este ejemplo para hacer una sugerencia incorrecta. Lo uso aquí para decir lo contrario -> Usar una declaración predeterminada):
El jugador podría presionar cualquier otra tecla. Entonces no podríamos hacer nada (esto se puede mostrar en el código simplemente agregando un comentario al caso predeterminado) o debería, por ejemplo, imprimir algo en la pantalla. Este caso es relevante ya que puede suceder.
Declaraciones de cambio exhaustivas: esas declaraciones de cambio cubren todos los valores posibles, por ejemplo, una declaración de cambio en una enumeración de tipos de sistemas de calificación. Al desarrollar código la primera vez, es fácil cubrir todos los valores. Sin embargo, como somos humanos, existe una pequeña posibilidad de olvidar algunos. Además, si agrega un valor de enumeración más adelante, de modo que todas las instrucciones de cambio tengan que adaptarse para que sean exhaustivas, nuevamente se abre el camino al infierno de errores. La solución simple es una herramienta de análisis de código estático. La herramienta debe verificar todas las declaraciones de cambio y verificar si son exhaustivas o si tienen un valor predeterminado. Aquí un ejemplo de una declaración exhaustiva de cambio. Primero necesitamos una enumeración:
Entonces necesitamos una variable de esta enumeración como
GradeSystemType type = ...
. Una declaración de cambio exhaustiva se vería así:Entonces, si ampliamos el,
GradeSystemType
por ejemplo,System1To3
la herramienta de análisis de código estático debería detectar que no hay una cláusula predeterminada y que la declaración de cambio no es exhaustiva, por lo que estamos guardados.Solo una cosa adicional. Si siempre usamos una
default
cláusula, podría suceder que la herramienta de análisis de código estático no sea capaz de detectar sentencias de cambio exhaustivas o no exhaustivas, ya que siempre detecta ladefault
cláusula. Esto es súper malo ya que no seremos informados si ampliamos la enumeración por otro valor y olvidamos agregarlo a una declaración de cambio.fuente
¿Las declaraciones de cambio siempre deben contener una cláusula predeterminada? No pueden existir casos de cambio sin el caso predeterminado, en el caso de cambio el caso predeterminado activará el valor del cambio
switch(x)
en este caso x cuando no coincida con ningún otro valor de caso.fuente
Creo que esto es bastante específico del lenguaje y para el caso de C ++ un punto menor para el tipo de clase enum . Que parece más seguro que el tradicional enum. PERO
Si observa la implementación de std :: byte es algo así como:
Fuente: https://en.cppreference.com/w/cpp/language/enum
Y también considere esto:
Fuente: https://en.cppreference.com/w/cpp/language/list_initialization
Este es un ejemplo de clase enum que representa valores que no son enumeradores definidos. Por esta razón, no puede confiar completamente en las enumeraciones. Dependiendo de la aplicación, esto puede ser importante.
Sin embargo, realmente me gusta lo que dijo @Harlan Kassler en su publicación y comenzaré a usar esa estrategia en algunas situaciones.
Solo un ejemplo de clase enum insegura:
fuente