Usos apropriados de instruções de chave fall-through


14

Quando é apropriado usar uma instrução de chave fall-through (clássica)? Esse uso é recomendado e incentivado ou deve ser evitado a todo custo?


Nem todos os idiomas permitem informações detalhadas sobre as opções do switch.
Oded

@Oded, editado, adicionou a palavra "clássica". Nem todos os idiomas permitem cair, no entanto, eu insisto que é clássico)
shabunc

3
Se você está falando do dispositivo de Duffs , isso é uma coisa.
Oded

6
@Oded: Essa é a primeira coisa que a maioria das pessoas pensa, mas isso não é "apropriado". De acordo com isso , o próprio Duff disse: "Isso definitivamente fornece um argumento na discussão sobre se a opção deve passar por padrão, mas não tenho certeza se o argumento é a favor ou contra."
BlueRaja - Danny Pflughoeft 26/10

Respostas:


15

Aqui está um exemplo em que isso seria ú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;
}

Acho que esse tipo de coisa (onde um caso inclui o outro) é bastante raro, e é por isso que algumas linguagens mais recentes não permitem fallover ou exigem uma sintaxe especial.


13
Este exemplo, embora interessante, não possui o // INTENTIONAL FALL THROUGH HEREcomentário obrigatório de maiúsculas .
Russell Borogove 26/10/11

É igualmente fácil escrever esse código com a invasão da GetItemsForLevel(Info)chamada GetItemsForLevel(Warning)e assim por diante.
Caleb

@RussellBorogove: Absolutamente correto.
configurator

@ Caleb: Neste caso, sim. Mas e se as ligações fossem um pouco mais complicadas? Pode ficar um pouco peludo, enquanto a queda faz parecer simples. Devo observar que não sou realmente a favor do uso do fall through - só estou dizendo que pode ser útil em determinadas situações.
configurator

Não é o melhor exemplo. Há uma ordem dos níveis de aviso. Ao definir essa ordem, esse método reduz a uma única linha de itens de filtragem de código quando o nível do item é pelo menos igual ao nível desejado.
Kevin cline #

8

Eu os uso quando certas funcionalidades precisam ser aplicadas para mais de um valor. Por exemplo, digamos que você tenha um objeto com uma propriedade chamada operationCode. Se o código for igual a 1, 2, 3 ou 4, você deseja iniciarOperaçãoX (). Se for 5 ou 6, você deseja startOperationY () e 7 você startOperationZ (). Por que ter 7 casos completos com funcionalidade e quebras quando você pode usar fall-throughs?

Eu acho que é completamente válido em certas situações, especialmente se evitar 100 declarações if-else. =)


4
O que você está descrevendo é um switchcom vários cases vinculados ao mesmo código. Isso é diferente de uma falha, onde a execução de uma casecontinua na próxima por causa da falta de uma breakentre elas.
Blrfl 25/10

3
Realmente não importa, o fracasso é apenas a falta de uma declaração de interrupção, de modo que "cai" no próximo caso.
Yatrix # 25/11

Eu reformularia o cenário na sua resposta para refletir isso.
Blrfl 25/10

2
@ Yatrix: eu discordo. É muito diferente ter casos consecutivos executando exatamente o mesmo bloco de código do que omitir uma quebra. Um é rotineiro, o outro está longe disso (ime) - e o potencial de leitura incorreta e fluxo de controle não intencional é muito maior.
Quentin-starin

3
@ qes sim, é diferente, mas ambos são falhos. Ele perguntou quando / se seria apropriado. Dei um exemplo de quando aconteceria. Não era para ser um exemplo completo. Dependendo do idioma, ter declarações antes de um resumo pode não funcionar. Eu não acho que vai com c # stackoverflow.com/questions/174155/…
Yatrix 26/10/11

8

Eu os usei ocasionalmente, acho que é sempre o uso apropriado - mas somente quando incluído no comentário apropriado.


7

Casos de queda são perfeitamente adequados. Costumo achar que uma enumeração é usada em muitos lugares e que, quando você não precisa diferenciar alguns casos, é mais fácil usar a lógica fall-through.

Por exemplo (observe os comentários 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;
  }
}

Acho esse tipo de uso perfeitamente aceitável.


Observe que há uma grande diferença entre case X: case Y: doSomething()e case X: doSomething(); case Y: doAnotherThing(). No primeiro, a intenção é bastante explícita, enquanto no segundo, a queda pode ser intencional ou não. Na minha experiência, o primeiro exemplo nunca dispara nenhum aviso nos compiladores / analisadores de código, enquanto o segundo exemplo. Pessoalmente, eu chamaria apenas o segundo exemplo de "falha" - embora não tenha certeza de uma definição "oficial".
Jens Bannmann

6

Isso depende de:

  • sua preferência pessoal
  • padrões de codificação do seu empregador
  • a quantidade de risco envolvida

Os dois principais problemas associados a deixar um caso passar para o próximo são:

  1. Isso torna seu código dependente da ordem das instruções de caso. Não é esse o caso, se você nunca falha, e acrescenta um grau de complexidade que geralmente não é bem-vindo.

  2. Não é óbvio que o código para um caso inclua o código para um ou mais casos subsequentes.

Alguns lugares proíbem explicitamente a queda. Se você não trabalha em um lugar desses e se sente confortável com a prática, e se a quebra do código em questão não causar nenhum sofrimento real, talvez não seja a pior coisa do mundo. Se você fizer isso, certifique-se de colocar um comentário chamativo nas proximidades para avisar aqueles que virão mais tarde (incluindo o futuro que você).


4

Aqui está um exemplo rápido (reconhecidamente incompleto (sem manipulação especial do ano bissexto)) de queda, tornando minha vida mais simples:

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

5
Embora isso seja meio inteligente, o tempo que você economiza para fazer isso será muito maior do que o tempo que leva para outras pessoas descobrirem o que isso faz. Além disso, você pode obter um melhor desempenho removendo o aspecto de falha, ou seja, 31 + 28 + 31 é sempre 90. Se você fizer isso, pode apenas colocar os totais nos casos, pois há apenas 11 a serem considerados.
21716 JimmyJames #

Você está certo, meu exemplo é definitivamente artificial :) Eu direi, no entanto, é mais fácil detectar um bug oculto quando o número de dias é especificado dessa maneira, em vez de pré-calcular todos os dias cumulativos para cada caso do comutador .
AaronDanielson

2
Eu garanto que, mas fazer isso em uma declaração constante seria preferível, por exemplo, FEB_START = 31; MAR_START = FEB_START + 28; etc., sem ter certeza de qual idioma é esse, mas em muitos, ele seria computado em tempo de compilação. A questão maior aqui é que é um pouco obtuso. Não tanto que é uma má idéia, apenas atípica. A menos que haja um benefício muito grande, geralmente é melhor ficar com expressões comuns.
21416 JimmyJames #

1
Excelente alternativa, usando constantes para os dias de início neste exemplo. De qualquer forma, o ponto aqui é que uma soma cumulativa é uma ótima utilidade para uma queda de caso de switch. Eu concordo 100% em usar expressões idiomáticas comuns, mas a natureza desta questão está se aventurando nas características mais esotéricas em que expressões difíceis são difíceis de encontrar.
AaronDanielson #

3

Se sinto necessidade de ir de um caso para outro (raro, é verdade), prefiro ser muito explícito e goto case, é claro, que assume que seu idioma é compatível.

Como o detalhamento é tão incomum e muito fácil de ignorar durante a leitura do código, acho apropriado ser explícito - e um passo, mesmo que seja um caso, deve se destacar como um dedo dolorido.

Também ajuda a evitar erros que podem ocorrer quando as instruções de caso são reordenadas.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.