Considera il seguente codice:
public void doSomething(int input)
{
while(true)
{
TransformInSomeWay(input);
if(ProcessingComplete(input))
break;
DoSomethingElseTo(input);
}
}
Supponiamo che questo processo comporti un numero finito di passaggi ma dipendenti dall'input; il loop è progettato per terminare da solo come risultato dell'algoritmo e non è progettato per funzionare indefinitamente (fino a quando non viene annullato da un evento esterno). Poiché il test per vedere se il ciclo dovrebbe terminare è nel mezzo di una serie logica di passaggi, il ciclo while stesso attualmente non controlla nulla di significativo; il controllo viene invece eseguito nel punto "corretto" all'interno dell'algoritmo concettuale.
Mi è stato detto che questo è un codice errato, perché è più soggetto a bug a causa della condizione finale non controllata dalla struttura del ciclo. È più difficile capire come usciresti dal ciclo e potresti invitare bug in quanto la condizione di rottura potrebbe essere aggirata o omessa per errore a causa di cambiamenti futuri.
Ora, il codice potrebbe essere strutturato come segue:
public void doSomething(int input)
{
TransformInSomeWay(input);
while(!ProcessingComplete(input))
{
DoSomethingElseTo(input);
TransformInSomeWay(input);
}
}
Tuttavia, questo duplica una chiamata a un metodo nel codice, violando DRY; se in TransformInSomeWay
seguito venissero sostituiti con qualche altro metodo, entrambe le chiamate dovrebbero essere trovate e modificate (e il fatto che ce ne siano due potrebbe essere meno ovvio in un pezzo di codice più complesso).
Puoi anche scriverlo come:
public void doSomething(int input)
{
var complete = false;
while(!complete)
{
TransformInSomeWay(input);
complete = ProcessingComplete(input);
if(!complete)
{
DoSomethingElseTo(input);
}
}
}
... ma ora hai una variabile il cui unico scopo è spostare il controllo delle condizioni sulla struttura del loop e deve anche essere verificato più volte per fornire lo stesso comportamento della logica originale.
Da parte mia, dico che dato l'algoritmo che questo codice implementa nel mondo reale, il codice originale è il più leggibile. Se lo stessi affrontando da solo, questo è il modo in cui ci penseresti, quindi sarebbe intuitivo per le persone che hanno familiarità con l'algoritmo.
Quindi, qual è il "migliore"? è meglio dare la responsabilità del controllo delle condizioni al ciclo while strutturando la logica attorno al ciclo? Oppure è meglio strutturare la logica in modo "naturale" come indicato dai requisiti o da una descrizione concettuale dell'algoritmo, anche se ciò può significare bypassare le funzionalità integrate del loop?
do ... until
costrutto è utile anche per questo tipo di loop poiché non devono essere "innescati".