Prémisse
Le code suivant doit être considéré comme une mauvaise forme, quelle que soit la langue ou la fonctionnalité souhaitée:
while( true ) {
}
Arguments à l'appui
La while( true )
boucle est de mauvaise forme car elle:
- Rompre le contrat implicite d'une boucle while.
- La déclaration de boucle while doit explicitement indiquer la seule condition de sortie.
- Implique qu'il boucle pour toujours.
- Le code dans la boucle doit être lu pour comprendre la clause de fin.
- Les boucles qui se répètent indéfiniment empêchent l'utilisateur de terminer le programme à partir du programme.
- Est inefficace.
- Il existe plusieurs conditions de terminaison de boucle, y compris la vérification de «vrai».
- Est sujet aux bugs.
- Impossible de déterminer facilement où placer le code qui s'exécutera toujours à chaque itération.
- Conduit à un code inutilement complexe.
- Analyse automatique du code source.
- Pour trouver des bogues, analyser la complexité du programme, vérifier la sécurité ou dériver automatiquement tout autre comportement de code source sans exécution de code, la spécification des conditions de rupture initiales permet aux algorithmes de déterminer des invariants utiles, améliorant ainsi les métriques d'analyse automatique du code source.
- Boucles infinies.
- Si tout le monde utilise toujours
while(true)
des boucles qui ne sont pas infinies, nous perdons la capacité de communiquer de manière concise lorsque les boucles n'ont en fait aucune condition de terminaison. (On peut soutenir que cela s'est déjà produit, donc le point est sans objet.)
Alternative à "Aller à"
Le code suivant est de meilleure forme:
while( isValidState() ) {
execute();
}
bool isValidState() {
return msg->state != DONE;
}
Avantages
Pas de drapeau. Non goto
. Pas exception. Facile à changer. Facile à lire. Facile à réparer. En plus le code:
- Isole la connaissance de la charge de travail de la boucle de la boucle elle-même.
- Permet à quelqu'un qui gère le code d'étendre facilement la fonctionnalité.
- Permet d'attribuer plusieurs conditions de fin en un seul endroit.
- Sépare la clause de fin du code à exécuter.
- Est plus sûr pour les centrales nucléaires. ;-)
Le deuxième point est important. Sans savoir comment fonctionne le code, si quelqu'un m'a demandé de faire en sorte que la boucle principale laisse aux autres threads (ou processus) un peu de temps CPU, deux solutions me viennent à l'esprit:
Option 1
Insérez facilement la pause:
while( isValidState() ) {
execute();
sleep();
}
Option 2
Remplacer l'exécution:
void execute() {
super->execute();
sleep();
}
Ce code est plus simple (donc plus facile à lire) qu'une boucle avec un embarqué switch
. La isValidState
méthode doit uniquement déterminer si la boucle doit continuer. La bête de somme de la méthode doit être abstraite dans la execute
méthode, ce qui permet aux sous-classes de remplacer le comportement par défaut (une tâche difficile utilisant un switch
et intégré goto
).
Exemple Python
Comparez la réponse suivante (à une question Python) qui a été publiée sur StackOverflow:
- Boucle pour toujours.
- Demandez à l'utilisateur de saisir son choix.
- Si l'entrée de l'utilisateur est «redémarrer», continuez à boucler indéfiniment.
- Sinon, arrêtez de boucler pour toujours.
- Fin.
Code
while True:
choice = raw_input('What do you want? ')
if choice == 'restart':
continue
else:
break
print 'Break!'
Contre:
- Initialisez le choix de l'utilisateur.
- Boucle tandis que le choix de l'utilisateur est le mot «redémarrer».
- Demandez à l'utilisateur de saisir son choix.
- Fin.
Code
choice = 'restart';
while choice == 'restart':
choice = raw_input('What do you want? ')
print 'Break!'
Ici, il en while True
résulte un code trompeur et trop complexe.