Premessa
Il codice seguente dovrebbe essere considerato una cattiva forma, indipendentemente dalla lingua o dalla funzionalità desiderata:
while( true ) {
}
Argomenti di supporto
Il while( true )
loop è di scarsa qualità perché:
- Rompe il contratto implicito di un ciclo while.
- La dichiarazione del ciclo while dovrebbe indicare esplicitamente l' unica condizione di uscita.
- Implica che funzioni per sempre.
- Il codice all'interno del ciclo deve essere letto per comprendere la clausola di chiusura.
- I cicli che si ripetono per sempre impediscono all'utente di terminare il programma dall'interno del programma.
- È inefficiente.
- Esistono più condizioni di terminazione del ciclo, incluso il controllo di "true".
- È soggetto a insetti.
- Non è possibile determinare facilmente dove inserire il codice che verrà sempre eseguito per ogni iterazione.
- Porta a codice inutilmente complesso.
- Analisi automatica del codice sorgente.
- Per trovare bug, analisi della complessità del programma, controlli di sicurezza o derivare automaticamente qualsiasi altro comportamento del codice sorgente senza l'esecuzione del codice, la specifica delle condizioni di interruzione iniziali consente agli algoritmi di determinare invarianti utili, migliorando così le metriche di analisi automatica del codice sorgente.
- Loop infiniti.
- Se tutti usano sempre
while(true)
cicli for che non sono infiniti, perdiamo la capacità di comunicare in modo conciso quando i cicli non hanno effettivamente una condizione di terminazione. (Probabilmente, questo è già successo, quindi il punto è discutibile.)
Alternativa a "Vai a"
Il codice seguente è una forma migliore:
while( isValidState() ) {
execute();
}
bool isValidState() {
return msg->state != DONE;
}
vantaggi
Nessuna bandiera. No goto
. Nessuna eccezione. Facile da cambiare. Facile da leggere. Facile da riparare. Inoltre il codice:
- Isola la conoscenza del carico di lavoro del loop dal loop stesso.
- Consente a qualcuno che mantiene il codice di estendere facilmente la funzionalità.
- Consente di assegnare più condizioni di terminazione in un'unica posizione.
- Separa la clausola di terminazione dal codice da eseguire.
- È più sicuro per le centrali nucleari. ;-)
Il secondo punto è importante. Senza sapere come funziona il codice, se qualcuno mi chiedesse di fare in modo che il ciclo principale lasci che altri thread (o processi) abbiano un po 'di tempo CPU, vengono in mente due soluzioni:
Opzione 1
Inserisci subito la pausa:
while( isValidState() ) {
execute();
sleep();
}
Opzione 2
Esegui override:
void execute() {
super->execute();
sleep();
}
Questo codice è più semplice (quindi più facile da leggere) di un ciclo con un file switch
. Il isValidState
metodo dovrebbe determinare solo se il ciclo deve continuare. Il cavallo di battaglia del metodo dovrebbe essere astratto nel execute
metodo, che consente alle sottoclassi di sovrascrivere il comportamento predefinito (un compito difficile utilizzando un switch
e incorporato goto
).
Esempio di Python
Confronta la seguente risposta (a una domanda di Python) che è stata pubblicata su StackOverflow:
- Loop per sempre.
- Chiedere all'utente di inserire la propria scelta.
- Se l'input dell'utente è "riavvia", continua il ciclo per sempre.
- Altrimenti, interrompi il ciclo per sempre.
- Fine.
Codice
while True:
choice = raw_input('What do you want? ')
if choice == 'restart':
continue
else:
break
print 'Break!'
Contro:
- Inizializza la scelta dell'utente.
- Esegui il ciclo mentre la scelta dell'utente è la parola "riavvia".
- Chiedere all'utente di inserire la propria scelta.
- Fine.
Codice
choice = 'restart';
while choice == 'restart':
choice = raw_input('What do you want? ')
print 'Break!'
Qui, si while True
traduce in codice fuorviante ed eccessivamente complesso.