Premissa
O código a seguir deve ser considerado um formato incorreto, independentemente do idioma ou da funcionalidade desejada:
while( true ) {
}
Argumentos de Apoio
O while( true )
loop é de má forma porque:
- Quebra o contrato implícito de um loop while.
- A declaração do loop while deve indicar explicitamente a única condição de saída.
- Implica que ele faz um loop para sempre.
- O código dentro do loop deve ser lido para compreender a cláusula de terminação.
- Os loops que se repetem para sempre evitam que o usuário finalize o programa de dentro do programa.
- É ineficiente.
- Existem várias condições de encerramento do loop, incluindo a verificação de "verdadeiro".
- Está sujeito a bugs.
- Não é possível determinar facilmente onde colocar o código que sempre será executado para cada iteração.
- Leva a um código desnecessariamente complexo.
- Análise automática de código-fonte.
- Para encontrar bugs, análise de complexidade de programa, verificações de segurança ou derivar automaticamente qualquer outro comportamento de código-fonte sem execução de código, a especificação da (s) condição (ões) de quebra inicial permite que os algoritmos determinem invariantes úteis, melhorando assim as métricas de análise automática de código-fonte.
- Loops infinitos.
- Se todo mundo sempre usa
while(true)
loops for que não são infinitos, perdemos a capacidade de nos comunicarmos concisamente quando os loops, na verdade, não têm condição de terminação. (Provavelmente, isso já aconteceu, então a questão é discutível.)
Alternativa para "Ir para"
O código a seguir é melhor:
while( isValidState() ) {
execute();
}
bool isValidState() {
return msg->state != DONE;
}
Vantagens
Sem bandeira. Não goto
. Sem exceção. Fácil de mudar. Fácil de ler. Fácil de consertar. Além disso, o código:
- Isola o conhecimento da carga de trabalho do loop do próprio loop.
- Permite que alguém que mantém o código estenda facilmente a funcionalidade.
- Permite que várias condições de encerramento sejam atribuídas em um só lugar.
- Separa a cláusula de terminação do código a ser executado.
- É mais seguro para usinas nucleares. ;-)
O segundo ponto é importante. Sem saber como o código funciona, se alguém me pedir para fazer o loop principal permitir que outros threads (ou processos) tenham algum tempo de CPU, duas soluções vêm à mente:
Opção 1
Insira prontamente a pausa:
while( isValidState() ) {
execute();
sleep();
}
Opção 2
Substituir executar:
void execute() {
super->execute();
sleep();
}
Este código é mais simples (portanto, mais fácil de ler) do que um loop com um incorporado switch
. O isValidState
método deve determinar apenas se o loop deve continuar. O burro de carga do método deve ser abstraído no execute
método, o que permite que as subclasses substituam o comportamento padrão (uma tarefa difícil usando um switch
egoto
).
Exemplo Python
Compare a seguinte resposta (a uma pergunta Python) que foi postada no StackOverflow:
- Loop para sempre.
- Peça ao usuário para inserir sua escolha.
- Se a entrada do usuário for 'reiniciar', continue o loop para sempre.
- Caso contrário, pare de repetir para sempre.
- Fim.
Código
while True:
choice = raw_input('What do you want? ')
if choice == 'restart':
continue
else:
break
print 'Break!'
Versus:
- Inicialize a escolha do usuário.
- Loop enquanto a escolha do usuário é a palavra 'reiniciar'.
- Peça ao usuário para inserir sua escolha.
- Fim.
Código
choice = 'restart';
while choice == 'restart':
choice = raw_input('What do you want? ')
print 'Break!'
Aqui, while True
resulta em código enganoso e excessivamente complexo.