Google Analytics

quinta-feira, 5 de abril de 2012

Uso robusto do default em switches

Noto uma grande tendência a usarem o default do switch para economizar digitação.

Por exemplo:

O cara tem 8 possíveis valores e tem de fazer o mesmo processamento para 6 deles; então coloca 2 cases e cobre os 6 comuns com um default. 

enum {V1, V2, V3, V4, V5, V6, V7, V8} v;
...

switch (v)
{
case V1:
  processV1();
case V2:
  processV2();
 
default:
  process3to8();
}

Funciona no dia em que é implementado. Mas é um pesadelo para manutenção. No dia que alguém incluir novos valores na enumeração, o novo valor vai ser "automagicamente" considerado como devendo ter o mesmo comportamento que o V3 a V8 tinham. O que pode estar errado. Coisas que acontecem automagicamente não são boas em programação. Por isso é uma boa prática se colocar os valores explicitamente e usar o default para logar erro indicando um valor inesperado (e, de preferência, abortar o programa imediatamente):

enum {V1, V2, V3, V4, V5, V6, V7, V8} v;
...


switch (v)
{
case V1:
  processV1();

case V2:
  processV2();

case V3:
case V4:
case V5:
case V6:
case V7:
case V8:
  process3to8();
default:
  /* Logar uma mensagem indicando que um valor inesperado ocorreu na variável v, da função tal... */
/* Sempre que possível, abortar o programa nesta situação. */
}


O ponto é que o default deve ser usado para expressar: Faça isto para todos os outros valores possíveis (tanto conhecidos quanto os desconhecidos). E não é bom programar para fazer coisas com valores desconhecidos.

O mesmo fenômeno ocorre para o else em trechos do tipo:

enum {V1, V2, V3, V4} v;
...
v = getValueFromSomewhere()

if(v== V1|| v==V2)
  doSomething()
else //Tratando o V3 e V4 como genérico (isto não é bom...)
  doOtherStuff();


Melhor seria usar algo como:

if (v== V1|| v==V2)
{
  doSomething()
 }
else if (v== V3 || v == V4)
{

   doOtherStuff();
 }
else
{
  DebugLog <<"Unexpected value received  in function XXXX. Value is " << v;
  abort();
}

Era isto.

Um comentário:

  1. Acho uma pena em C/C++ não ser possível declarar todos valores que requerem o mesmo tratamento numa única linha, como:

    case V3, V4, V5, V6, V7, V8:

    Botar cases um embaixo do outro é uma abominação (não por culpa do programador, é claro).

    Anyway, o "default" sempre será importante!

    ResponderExcluir