Conditions multiples d'interruptions d'une instruction
Par -Alexandre LEGOUT aka LAlex- le 5 avril 2004, 09:11 - AS2 - Lien permanent
Il arrive parfois que l'on ai besoin que plusieurs conditions soient remplies pour executer une instruction finale. Dans le cas où une des conditions n'est pas remplie, les tests suivants ne sont plus nécessaires, et il peut être important de ne pas les tester en terme d'optimisation. Quand ces conditions sont nombreuses, on peut se retrouver avec une grosse imbrication de if ... else, qui en plus de nuire terriblement à la lisisbilité du code, augmentent la complexité de celui-ci (la compléxité d'un code se calcule entre autre avec le nombre d'instructions if imbriquées.
Il est vrai qu'une simplification pourrait consister à utiliser des ET logiques (&&) dans un ordre défini, comme je l'explique dans ce post, mais si certaines conditions doivent être succédées par un traitement, ce système ne fonctionne plus.
Le problème s'est posé à moi pour la nouvelle version de mon moteur de blog, olrs de l'ajout d'un commentaire. En effet, si le nom est vide, je n'ai pas besoin de tester le contenu du commentaire. Si le commentaire est vide, je n'ai pas besoin de tester la valididté de l'email, etc... Si l'une de ces conditions est fausse, l'enregistrement du commentaire ne doit pas se faire. Cette astuce est valable pour tout langage, je vais donc l'illustrer ici en AS2.
Voici donc le code que l'on peut s'attendre à avoir :// Test du nom
Evidemment, les moyens de simplifier le code sont nombreux : création d'une variable booleenne spécifiant si une erreur est survenue, stockage du message d'erreur pour n'avoir qu'une instruction trace(), etc... Mais si le code présenté ici est simple, ce n'est pas toujours le cas. Et quoi qu'il arrive, tester si une erreur est déja survenue rajoute un [i]if[/if] à chaque test de condition ...
Une solution que j'ai trouvée consiste à utilise l'instruction do ... while conjugée avec break pour arrêter le traitement dés qu'une erreur est trouvée. Cela correspond en fait à un goto, que l'on rencontre dans certains langages:
if (!this.name.length) {
trace("Le nom est obligatoire");
} else {
// Test du commentaire
if (!this.comment.length) {
trace("Le commentaire est obligatoire");
} else {
// Test de l'adresse email
if (!this.isValidEmail(this.email)) {
trace("L'adresse email saisie n'est pas valide");
} else {
// Enregistrement du commentaire
this.saveComment();
}
}
}// Message d'erreur eventuel
var err = false;
// Première et dernière boucle
do {
// Test du nom
if (!this.name.length) {
err = "Le nom est obligatoire";
break;
}
// Test du commentaire
if (!this.comment.length) {
err = "Le commentaire est obligatoire";
break;
}
// Test du mail
if (!this.isValidEmail(this.email)) {
err = "L'adresse email saisie n'est pas valide";
break;
}
// Enregistrement du commentaire
this.saveComment();
// Le while(false) interromps la boucle dés le premier passage
} while (false);
// S'il y a eu une erreur, on l'affiche
if (err) {
trace(err);
}
Cet exemple présente une situation assez simple, qui est facilement optimisable d'autres manières. Mais cette utilisation du do...while peut-être bien pratique dans des situations plus complexes ... ![]()
Commentaires
Le 'do...while' avec des 'break' est astucieux mais pas forcément un grand gain de clareté (pourquoi ne pas utiliser un 'switch' aussi ?).
Je suis plutôt pour la création de fonctions de vérification - en plus de cette manière la validation de ton formulaire est indépendante de la validation de chaque champ :
if (this.isValidName() && this.isValidComment() && this.isValidEmail())
this.saveComment();
C'est chaque fonction de test qui va effectuer les traitements nécessaires (comme afficher une information d'erreur).
cela dépend des traitements à effectuer dans les fonctions de vérification. On peut considérer que c'est leur rôle d'afficher un message d'erreur (quoi que, je dirais plus que l'erreur doit être émise par une instruction qui appele isValid()). Si une fois que le nom est certifié valide, tu dois par exemple l'insérer dans une base pour une raison X ou Y, ou effectuer des traitements.
Par exemple, dans la notification par e-mail, si le mail est valide, non seulement je peux insérer le commentaire, mais je dois aussi le rajouter aux notifications. Je parle de manière générale d'un ensemble de conditions alternées par des traitements quelconques, ou chacune des conditions peut mettre fin à la totalité des traitements suivants.
Comme je le dis, cet exemple reste un exemple : il aurait été préférable de faire de l'interception d'erreur (try ... catch) plutôt que le if(err). Il est optimisable de bien des manières, mais cette astuce du do...while peut être une solution bien pratique dans des cas plus complexes !
aaa enfin de retour!:D
pas mal comme concept mais je prefere utiliser le try..catch
monsieurfil >> C'est chaque fonction de test qui va effectuer les traitements nécessaires (comme afficher une information d'erreur).
je crois qu'il serait mieu de ne pas meler la logique et l'affichage, sinon leur utilisation sera limité que dans ce contexte
A++
Evidemment !
Mais certains langages ne le possèdent pas encore : en fait, ce problème s'est posé à moi en PHP4. Heureusement PHP5 regle le problème ! 
++ ^^
D'ailleurs, pour ceux qui ne connaissent pas (encore) le try...catch en ActionScript 2, je rappelle l'article que j'ai fait à ce sujet !
Bon dans ma technique, les profs ont beaucoup mis l'emphase sur un point et c'est justement de ne pas utiliser des instructions comme break, next, exit puisque c'est la preuve d'un code déficient. Même pour l'utilisation de plusieurs instructions return dans une fonction. Donc ma technique est la variable booléen ou le positionnement logique des &&. Le seul moment possible d'utiliser des break, c'est quand t'es en temps réel dans un thread ou tout autre code qui doit rouler en boucle puisque là, c'est une question de bon fonctionnement et de perdre le moins d'informations possibles.
En quoi est-ce la preuve d'un code déficient ? 8O
En puis à partir d'un certain degré d'optimisation, il arrive souvent que le pratique aille à l'encontre de la théorie ...
Quoi qu'il arrive, en l'absence d'instruction d'interception d'erreurs, cette solution me parait clairement la meilleure ... 
++ ^^
moi je suis un partisan du break;) bien que les profs déconseillent cette technique, elle optimise le code et en diminue le nombre de ligne... déficient est un gros mot... Mais je suis d'accord avec eux pour ce qui est du goto...
A+
Bah c'est simple, y'a parfois que ça peut être bien utilisé, mais trop souvent c'est des expressions qui étaient très mal utilisé. Et un autre élève a vu un cas flagrant dans son stage.
while( 1=1 )
{
...série de if et de break
]
Mais selon-moi, le pire c'est un code de 600 lignes non documenté ou très mal documenté. C'est pire que les break
Le seul moment possible d'utiliser des break, c'est quand t'es en temps réel dans un thread ou tout autre code qui doit rouler en boucle puisque là, c'est une question de bon fonctionnement et de perdre le moins d'informations possibles.Personnelement, c'est la seule façon dont je l'utilise et j'ai du mal à comprendre comment l'utiliser autrement!
J'aimerais bien voir des exemples de codes où il est utiliser autrement.
Roikku > Regarde le contenu de ce que je dit dans le post !
Bof, si bien utilise, le goto est carrement puissant. Il y avait un thread interessant a ce sujet l'annee derniere dans la liste du noyau linux. Il y en a un resume avec les posts principaux ici:
http://kerneltrap.org/node/view/553/2139
Jette un coup d'oeil au morceau de code de Robert Love tout en bas. Que c'est beau le goto
Sinon, j'aime bien ta technique Lalex, c'est vrai que ca manque parfois le goto donc j'utilise ca de temps en temps. Et aussi des fonctions avec des returns des qu'une condition est invalide. Tout le contraire de ce que tu disais, Nambew, en fait. J'aurais sans doute des sales notes avec tes profs ;). Par contre je suis d'accord avec les exit, un program qui sort n'importe ou n'importe comment c'est pas gerable et la faut vraiment faire propre.
Sinon on a toujours le goto/jump avec flasm, tout n'est pas perdu en AS
Oui, j'utilise trés souvent le return pour éviter des tests inutiles dans mes fonctions ...
Bah je peux te dire que ça dépend vraiment des cours et des profs vu que dans mon cours de DirectX, c'était fréquent de voir plusieurs return et c'est selon moi pas une si mauvaise chose, mais bon là au ça se complique, c'est si t'as 10 return dans la fonction et comme par malheur, un jour tu dois ajouter un bout de code à la fin de ta fonction qui doit s'exécuter peu importe la valeur renvoyer. C'est selon moi pour la même raison que les profs suggèrent de ne pas utiliser le break. Mais dans certains cours, on perdait des points dès qu'on ne respectait pas une norme à moins d'avoir un argument béton en commentaire.
Pour moi ... tout est bon (ou presque) .. mais tout dépend du contexte
Utiliser un return dans un switch dans une fonction servant "getter" au lieu d'un break je vois pas où serait le problème ? faire une série de if/else if... niveau lisibilité du code je suis pas fan.
bye
Dur, mais bon ca se comprend: dans une boite, faut suivre les guides de code a la lettre alors c'est un bon entrainement de faire ca des les cours.
Et puis le code c'est comme la musique ou la poesie, d'abord il faut apprendre les regles, et apres on verra avec l'experience comment toutes ces regles peuvent etre contournees pour faire quelque chose de plus beau. On est des artistes quoi. Snif, c'est beau ce que je dis quand meme :P.
Quel pouet ce tim' !!!
Mais c'est tellement vrai
Fil des commentaires de ce billet