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
Le site while( true )
la boucle est une mauvaise forme parce qu'elle :
-
Brise le contrat implicite d'une boucle while.
- La déclaration de la boucle while doit indiquer explicitement le sólo état de sortie.
-
Cela implique qu'il tourne en boucle pour toujours.
- Le code à l'intérieur de la boucle doit être lu pour comprendre la clause de terminaison.
- Les boucles qui se répètent indéfiniment empêchent l'utilisateur de mettre fin au programme depuis l'intérieur de celui-ci.
-
Est inefficace.
- Il existe plusieurs conditions de fin de boucle, y compris la vérification de "vrai".
-
est sujet à des bogues.
- Impossible de déterminer facilement où placer le code qui sera toujours exécuté pour chaque itération.
- Conduit à un code inutilement complexe.
-
Analyse automatique du code source.
- Pour trouver des bogues, analyser la complexité des programmes, effectuer des contrôles de sécurité ou déduire automatiquement tout autre comportement du code source sans exécution du code, la spécification de la ou des conditions de rupture initiales permet aux algorithmes de déterminer des invariants utiles, améliorant ainsi les mesures d'analyse automatique du code source.
-
Boucles infinies.
- Si tout le monde utilise toujours
while(true)
pour les boucles qui ne sont pas infinies, nous perdons la capacité de communiquer de manière concise lorsque les boucles n'ont pas de condition de terminaison. (On peut soutenir que cela s'est déjà produit, donc le point est discutable).
Alternative à "Aller à"
Le code suivant est une meilleure forme :
while( isValidState() ) {
execute();
}
bool isValidState() {
return msg->state != DONE;
}
Avantages
Pas de drapeau. Non goto
. Aucune exception. Facile à changer. Facile à lire. Facile à réparer. En plus du code :
- Isole la connaissance de la charge de travail de la boucle de la boucle elle-même.
- Permet à la personne qui maintient le code d'étendre facilement la fonctionnalité.
- Permet d'attribuer plusieurs conditions de terminaison en un seul endroit.
- Sépare la clause de terminaison du code à exécuter.
- est plus sûr pour les centrales nucléaires ;-)
Le deuxième point est important. Sans connaître le fonctionnement du code, si quelqu'un me demandait de faire en sorte que la boucle principale laisse à d'autres threads (ou processus) du temps CPU, deux solutions me viennent à l'esprit :
Option 1
Insérer rapidement la pause :
while( isValidState() ) {
execute();
sleep();
}
Option n° 2
Annulez l'exécution :
void execute() {
super->execute();
sleep();
}
Ce code est plus simple (et donc plus facile à lire) que celui d'une boucle avec une fonction switch
. Le site isValidState
devrait seulement déterminer si la boucle doit continuer. La partie la plus importante de la méthode doit être abstraite et intégrée dans la fonction execute
qui permet aux sous-classes de remplacer le comportement par défaut (une tâche difficile si l'on utilise une méthode intégrée switch
y goto
).
Exemple Python
Comparez la réponse suivante (à une question sur Python) qui a été publiée sur StackOverflow :
- Bouclez pour toujours.
- Demandez à l'utilisateur de saisir son choix.
- Si l'entrée de l'utilisateur est 'restart', continuer la boucle pour toujours.
- Sinon, arrêtez la boucle pour toujours.
- Fin.
Code
while True:
choice = raw_input('What do you want? ')
if choice == 'restart':
continue
else:
break
print 'Break!'
Versus :
- Initialiser le choix de l'utilisateur.
- Boucle alors que le choix de l'utilisateur est le mot "redémarrage".
- Demandez à l'utilisateur de saisir son choix.
- Fin.
Code
choice = 'restart';
while choice == 'restart':
choice = raw_input('What do you want? ')
print 'Break!'
Aquí, while True
aboutit à un code trompeur et excessivement complexe.
23 votes
Pourquoi avez-vous besoin d'une rupture conditionnelle après l'interrupteur ? Changez simplement votre while de while(true) à while(flag)...
8 votes
@Dave_Jarvis Je suppose que c'est une version simplifiée qu'il a mise ici pour illustrer ce qu'il essayait de faire.
0 votes
Voir : Code complet (2e éd.). Voir aussi 'Structured Programming with goto statements' par D E Knuth ( pplab.snu.ac.kr/cours/adv_pl05/papers/p261-knuth.pdf ).
1 votes
@Tal Pressman et al : il me semble que cela pourrait être une machine à table d'états, avec un cas pour chaque état - y compris un état DONE dans lequel le code devrait sortir. Cependant, cela pourrait peut-être être géré par '
while (msg->state != DONE)
' pour le contrôle de la boucle.0 votes
@Jonathan. Oui, exactement. J'irais même plus loin en séparant les préoccupations de la condition de terminaison de la boucle de la boucle elle-même (en l'extrayant vers une méthode).
6 votes
Si vous faites partie de ces programmeurs qui produisent des fonctions de plusieurs pages, vous trouverez que
goto
attrayante et, parfois, la seule issue propre. Si vous avez tendance à organiser votre code en petites fonctions de quelques lignes seulement, qui ne font qu'une seule chose chacune, vous ne rencontrerez jamais ce problème. (Accessoirement, votre code sera aussi plus facile à lire).17 votes
C'est comme si on vous conseillait d'arrêter de fumer alors que tout ce que vous voulez savoir, c'est comment vous rendre à la station de métro la plus proche.
8 votes
@hacker : Si vous ne pouvez pas voir la station de métro en face de vous à cause de la fumée, ce conseil n'est peut-être pas si mauvais.
:)
0 votes
Parfois, il est pratique d'appeler le retour d'une affaire. Pas très joli, mais ça marche.
0 votes
Vous pouvez toujours utiliser if-else, sauf si vous avez trop de cas !
0 votes
@sbi Si vous êtes un de ces programmeurs qui n'écrivent que des fonctions de quelques lignes, alors par définition vous n'utilisez/écrivez pas d'instructions switch-case (bien formatées) ;) (en fonction de votre définition de "peu") Mais oui, vous pouvez généralement le décomposer un peu (déplacer la boucle while dans sa propre fonction, utiliser return)... bien que cela ne rende pas toujours le code plus lisible. Si je regroupais chaque paire d'instructions dans une fonction, je pourrais écrire du code qui se lit comme un arbre binaire :) Essayez simplement d'écrire des morceaux lisibles qui vont ensemble de sorte que la recherche de fonctions ne casse pas le flux de lecture.
0 votes
@Steven Qui a dit que je regroupais "chaque paire d'instructions en une fonction" ?
0 votes
@sbi Je ne sais pas ? Qui a dit ça ? Je n'ai certainement pas dit que vous l'aviez dit. J'ai juste essayé d'illustrer mon propos, à savoir que plus court n'est pas toujours synonyme de code plus lisible. Mais c'est généralement le cas, donc c'est une bonne pratique de diviser le code en morceaux complets les plus courts possibles, mais pas plus courts IMO. [Je ne sais pas comment déplacer cette conversation hors de ce fil de commentaires, mais je suis curieux de savoir ce que vous pensez de l'utilisation des gotos par libtomcrypt. Avez-vous une façon élégante et plus lisible de le faire ? ]