L'objectif premier d'un programme informatique est d'automatiser des tâches (souvent répétitives) mais n'oublions pas qu'il va s'adresser à des utilisateurs humains qui auront envie ou besoin d'effectuer des choix que votre programme ne peut anticiper. Nos programmes doivent donc en tenir compte et gérer ces choix : « SI l'utilisateur fait tel choix ALORS faire ceci SINON faire cela ».
Nous profiterons également de ce chapitre pour voir différents opérateurs permettant de comparer nos variables. Le programme étant suffisamment chargé, ce chapitre est scindé en deux parties pour plus de clarté. Dans la seconde partie nous aborderons l'algèbre booléenne, terme effrayant mais qui recouvre des règles de logique qui nous permettront de gérer des conditions plus complexes.
- Conditions simples avec IF
- Conditions multiples avec IF
- Conditions multiples avec CASE
- Les opérateurs de comparaison et d'appartenance
- Pour les utilisateurs de la norme Ada2012
Conditions simples avec IF
Un début en douceur
Nous allons réaliser ici, un programme qui demande à son utilisateur s'il dispose de plusieurs ordinateurs. Cette question n'appellera que deux choix possibles : Oui ou Non. Le programme renverra un message à l'écran qui dépendra de la réponse obtenue. Ce programme peut se décomposer de la manière suivante :
1 2 3 4 | AFFICHER la question : "Avez-vous plusieurs ordinateurs ?" SAISIR la réponse (Oui ou Non) SI la réponse est oui ALORS AFFICHER : "Vous avez bien de la chance." |
Nous enregistrerons la réponse dans une variable Reponse qui sera de type Character. L'utilisateur devra taper "o", pour oui, et "n", pour non. L'instruction SI se note IF
en Ada et l'instruction ALORS se note quant à elle THEN
.
D'où le code suivant :
1 2 3 4 5 6 7 8 9 10 11 | PROCEDURE Questionnaire IS Reponse : Character := 'n' ; --on définit Reponse et on lui attribue --par défaut la valeur n (pour non) BEGIN Put("Avez-vous plusieurs ordinateurs ? (o/n) ") ; Get(Reponse) ; Skip_line ; --On saisit la réponse et on vide la mémoire tampon IF Reponse = 'o' --SI Reponse est égal à o THEN Put("Vous avez bien de la chance."); --ALORS on affiche la phrase. END IF ; END Questionnaire ; |
Mais pourquoi tu as écrit = et non pas := comme avant ?
Tout simplement parce que le symbole := est utilisé pour affecter une valeur à une variable. Si nous avions écrit «Reponse := 'o' ;
», alors nous aurions modifier la valeur de Reponse en lui attribuant la valeur 'o'
. Or, ici nous posons une question au programme : Reponse est-il bien égal à 'o'
? Le programme se chargera de répondre vrai ou faux. C'est pourquoi, nous utiliserons ici le symbole =. D'ailleurs, après une instruction IF
, le compilateur refuserait que vous utilisiez le symbole :=.
Autres remarques, l'instruction IF
doit être clôturée par une instruction END IF
qui marquera la fin des actions à exécuter. Et s'il ne faut pas de « ; » à la fin de l'instruction IF
, il en faut bien après END IF
!
Mais ce programme présente de grosses lacunes. Que se passe-t-il si l'utilisateur répond non (n) ? Eh bien pour l'instant, c'est très simple : rien.
Une première alternative
Nous allons donc compléter notre code de la manière suivante :
1 2 3 4 5 | AFFICHER la question : "Avez-vous plusieurs ordinateurs ?" SAISIR la réponse (Oui ou Non) SI la réponse est oui ALORS AFFICHER : "Vous avez bien de la chance." SINON AFFICHER : "Ha… Dommage." |
L'instruction SINON se traduit par ELSE
et nous permettra de varier un peu notre programme. Au lieu d'avoir le code suivant :
1 2 3 | if Reponse = 'o' then Put("Vous avez bien de la chance.") ; end if ; |
Nous allons donc écrire :
1 2 3 4 | if Reponse = 'o' then Put("Vous avez bien de la chance.") ; else Put ("Ha ... Dommage. ") ; end if ; |
Désormais, si l'utilisateur répond non (n), il recevra tout de même une réponse, différente qui plus est !
Et que se passerait-il si l'utilisateur tapait une autre lettre, comme z par exemple ?
Pour avoir la réponse reprenons notre code ! Celui-ci ne teste qu'une seule égalité : la variable Reponse est-elle égale à 'o'
? Donc si Reponse vaut 'z'
, le programme apportera la même réponse que si elle vaut 'n'
, 'a'
, '@'
ou autre ! Dit différemment, nous n'avons pas envisagé tous les cas. L'utilisateur peut tout à fait répondre autre chose que oui ou non. Et là, vous vous demandez s'il n'existerait pas une troisième instruction après THEN
et ELSE
. Eh bien non. Pour envisager d'avantage de cas, il va falloir ruser.
Conditions multiples avec IF
L'astuce (pas si compliquée d'ailleurs) est de réaliser plusieurs tests :
1 2 3 4 5 | SI la réponse est oui ALORS AFFICHER ("Vous avez bien de la chance") SINON SI la réponse est non ALORS AFFICHER("Ah… Dommage.") SINON Afficher("C'est pas une réponse ça !") |
Il est en effet possible d'imbriquer plusieurs instructions IF
les unes dans les autres.
1 2 3 4 5 6 7 | if Reponse = 'o' then Put("Vous avez bien de la chance"); --cas où la réponse est oui else if Reponse = 'n' then Put("Ah… Dommage."); --cas où la réponse est non else Put("C'est pas une réponse ça !"); --cas où la réponse est… autre chose end if ; end if ; |
Et voilà, le tour est joué ! Allez, plus compliqué maintenant. Si l'utilisateur répond 'p'
(pour «p'têt bin que oui, p'têt bin que non») on affichera le message suivant: «Reponses normandes non valides». À vous de jouer!
1 2 3 4 5 6 7 8 9 10 | if Reponse = 'o' then Put("Vous avez bien de la chance"); else if Reponse = 'n' then Put("Ah… Dommage."); else if Reponse = 'p' then Put("Reponses normandes non valides"); else Put("C'est pas une réponse ça !"); end if ; end if ; end if ; |
Alors vous avez réussi ? Bien joué ! Regardez toutefois le code que je vous propose. À chaque nouveau THEN/ELSE
, j'ai ajouté une tabulation (ou 3 espaces avec Adagide). Nous avons déjà vu cette pratique, elle s'appelle l'indentation. Elle n'est pas anodine car elle vous permettra de proposer un code aéré, organisé et donc facilement lisible par vous ou un tiers. Prenez cette habitude le plus tôt possible ! C'est un conseil que je ne cesserai de vous répéter.
Toutefois, vous avez dû vous rendre compte que cela devient vite fatiguant d'écrire plusieurs END IF
et d'augmenter de plus en plus le nombre de tabulations pour avoir un code bien indenté. Heureusement les instructions ELSE IF
peuvent être remplacées par une autre : ELSIF
!
Et ça change quoi ? (À part une lettre en moins)
Et bien, observez par vous-même :
1 2 3 4 5 6 7 8 | if Reponse = 'o' then Put("Vous avez bien de la chance"); elsif Reponse = 'n' then Put("Ah… Dommage."); elsif Reponse = 'p' then Put("Reponses normandes non valides"); else Put("C'est pas une réponse ça !"); end if ; |
Plus besoin de multiplier les END IF
. Du coup, chaque instruction ELSIF
se présente comme un «prolongement» du IF
initial, limitant ainsi l'indentation. Mais il y a une instruction encore plus lisible et particulièrement appropriée pour des choix multiples: la condition multiple avec CASE
.
Conditions multiples avec CASE
Tester de nombreux cas
Cette nouvelle instruction s'appelle CASE
. Comme son nom l'indique (si vous êtes un peu anglophone), elle permet de traiter différents CAS (= case). Alors pour la beauté de l'art, nous allons ajouter un cas supplémentaire. Si l'utilisateur appuie sur 'f'
(pour «I don't speak French» = «Je ne parle pas français» pour les anglophobes), alors…
1 2 3 4 5 6 7 | case Reponse is --on indique que l'on va regarder les différents cas possibles pour Reponse when 'o' => Put("Vous avez bien de la chance.") ; -- si oui when 'n' => Put("Ah… dommage. ") ; -- si non when 'p' => Put("Reponses normandes non valides") ; -- si peut-être when 'f' => Put("J'aurais pas du apprendre l'allemand…") ; -- si "not French" when others => Put("C'est pas une reponse.") ; -- si autre chose end case ; -- on termine notre instruction comme avec if ! |
Cette nouvelle instruction a des avantages : plus compacte, elle est donc plus claire, plus lisible et surtout plus rapide à taper lorsque les choix s'avèrent nombreux. Elle présente toutefois des limites que nous verrons dans les prochaines parties.
Pour l'instant regardons la structure. La portion de code ci-dessus (on parlera de bloc) est introduite de la même manière que la procédure de votre programme : PROCEDURE Questionnaire IS
. Elle se termine par END CASE
. Les flèches sont composées du signe égal (=) suivi du signe «supérieur à» (>). Rappelons enfin que le mot WHEN
signifie QUAND et que le mot OTHERS
signifie AUTRE (n'utilisez l'instruction WHEN OTHERS
qu'après avoir traité tous les cas désirés et afin de traiter tous les autres cas possibles).
Vous avez bien compris ? Alors rien ne vous empêche de trouver d'autres réponses farfelues pour vous exercer. Pensez toutefois à indiquer ces nouvelles réponses possibles à l'utilisateur. Je vous invite à reprendre les parties précédentes si vous avez encore quelques doutes car la partie suivante sera un peu plus compliquée.
En effet, nous pensions avoir fini notre programme, que nous avions vus tous les choix possibles, etc. Et bien non. Que se passera-t-il si l'utilisateur tape 'O'
au lieu de 'o'
, ou bien 'N'
au lieu de 'n'
? Pour l'ordinateur, un «n» minuscule et un «N» majuscule sont deux valeurs différentes. Il considèrera que c'est une mauvaise réponse et répondra donc "C'est pas une reponse"
!
On va devoir créer 4 nouveaux cas pour les majuscules ?
Non, rassurez-vous. Nous allons toutefois devoir faire un peu de logique : c'est ce qu'on appelle l'algèbre booléenne, mais nous ne l'aborderons pas dans ce chapitre. Si certaines choses ne sont pas claires, je vous conseille de relire ce chapitre car le suivant s'avèrera plus compliqué.
Ne rien faire
Une instruction CASE
doit vérifier toutes les valeurs que peut prendre la variable testée. Dans notre exemple, la variable Reponse peut prendre une très grande quantité de valeurs allant de l'arobase au symbole dollar. Pour ne pas coder tous ces tests manuellement, Ada a prévu l'instruction OTHERS
qui regroupe tout ce qui n'a pas été testé.
Mais si je ne veux rien faire de particulier pour ces autres cas ?
Le langage Ada a tout prévu. Il existe une instruction pour ne rien faire : NULL
. Il suffira ainsi d'écrire «WHEN OTHERS => NULL ;
» à la fin pour régler ce menu problème.
L'instruction NULL
peut jouer d'autres rôles, notamment avec les pointeurs.
Les opérateurs de comparaison et d'appartenance
Les opérateurs de comparaison
Tous nos tests jusque là se contentaient de vérifier une égalité. Or, il est possible d'utiliser d'autres symboles mathématiques appelés opérateurs de comparaison. En voici un liste.
Opérateur |
Signification |
---|---|
= |
«est égal à» |
/= |
«est différent de» |
< |
«est plus petit que» |
> |
«est plus grand que» |
<= |
«est plus petit ou égal à» |
>= |
«est plus grand ou égal à» |
Ainsi, notre programme initial peut-être modifié de la manière suivante :
1 2 3 4 5 | AFFICHER "Combien d'ordinateurs avez-vous?" SAISIR la réponse SI la réponse est supérieure ou égal à 2 ALORS AFFICHER "Génial" SINON AFFICHER "C'est toujours ca" |
D'où le programme suivant :
1 2 3 4 5 6 7 8 9 10 11 12 | Procedure Questionnaire2 is Reponse : integer := 0 ; --on définit la réponse et on l'initialise à 0 begin Put("Combien d'ordinateurs avez-vous?") ; Get(Reponse) ; Skip_line ; if Reponse >= 2 then Put("Genial!") ; else Put("C'est toujours ca") ; end if ; end Questionnaire2 ; |
À noter que la question posée (Reponse est-elle supérieure ou égale à 2) , aussi appelée prédicat peut être remplacée par :
1 2 3 4 | if Reponse>1 then Put("Genial!") ; else Put("C'est toujours ca") ; end if ; |
Ce nouveau prédicat aura la même conclusion. De même, en inversant les instructions suivantes THEN
et ELSE
et en écrivant les codes suivants :
1 2 3 4 | if Reponse<=1 then Put("C'est toujours ca") ; else Put("Genial!") ; end if ; |
ou
1 2 3 4 | if Reponse<2 then Put("C'est toujours ca") ; else Put("Genial!") ; end if ; |
… On obtiendra également la même chose.
Règle de logique : le contraire de «<» n'est pas «>» mais bien «>=». Inversement, le contraire de «>» est «<=» !
Ces différents symboles (>, <, >= et <=) ne peuvent être utilisés lors d'une instruction CASE
. Pensez-y !
L'opérateur d'appartenance
Je dois enfin vous révéler un dernier test possible : le test d'appartenance. Nous avons vu qu'il était interdit de mélanger des variables de type Integer et de type Float, à moins d'effectuer un cast (une conversion). En revanche, je vous ai dit dès le départ que cette interdiction ne valait pas pour les Natural et les Integer, car le type natural n'est finalement qu'un sous-type d'Integer (un produit dérivé en quelque sorte). Voilà qui fait notre affaire : si nous avons une variable N de type Integer et que nous souhaitons tester si elle est positive ou nulle, il suffira de savoir si elle fait partie du sous-type des Natural à l'aide du mot-clé IN
et de l'attribut 'range
. Au lieu d'écrire :
1 2 | IF N >= 0 THEN ... |
Il sera possible d'écrire :
1 2 | IF N IN Natural'range THEN ... |
Petite traduction en Français : « Si N est dans l'intervalle des Natural ». Si N vaut -4
, ce prédicat vaudra FALSE
. De même, il est possible d'effectuer un test pour des intervalles plus restrictifs encore. Si nous souhaitons savoir si N est compris entre 13 et 32, il suffira d'écrire :
1 2 | IF N IN 13..32 THEN ... |
Attention, j'ai bien écrit deux points entre 13 et 32 ! Et pas trois points !
Pour les utilisateurs de la norme Ada2012
Les expressions IF
Si vous disposez d'un compilateur GNAT récent, celui-ci doit alors répondre à la toute dernière norme du langage, appelée Ada2012. Si ce n'est pas le cas, ce qui suit ne vous concerne pas. Cette norme n'est pas un nouveau langage mais « simplement » une mise à jour, une évolution. Entre autres améliorations, la norme Ada2012 s'est inspirée des langages de programmation dits « fonctionnels » pour proposer le concept d'expression. Ces langages (comme F#, Haskell ou OCaml) sont réputés pour donner naissance à des codes très compacts et minimalistes.
L'idée des expressions est de permettre d'utiliser les instructions IF
au sein même des affectations. Imaginons que suite à la réponse de l'utilisateur vous souhaitiez renseigner une autre variable pour abonder votre fichier client. Appelons cette variable Information
et déclarons-la de type Integer
. Si l'utilisateur a un ordinateur, Information vaudra 1 et 0 sinon. Voici comment nous procéderions avec le langage Ada dans ses 83, 95 ou 2005 :
1 2 3 4 | IF Reponse = 'o' THEN Information := 1 ; ELSE Information := 0 ; END IF ; |
Et voyez comment la norme Ada2013 nous permet de condenser notre code :
1 | Information := (IF Reponse = 'o' THEN 1 ELSE 0) ; |
Notez la disparition des points virgules et des deux affectations. L'expression permet d'affecter à notre variable la valeur 1 ou 0 en fonction du résultat du test. Nous pouvons également utiliser cette méthode pour l'affichage :
1 | Put(IF Reponse = 'o' THEN "Vous avez bien de la chance. " ELSE "Ah… Dommage.") ; |
Et, luxe suprême, il est même possible d'utiliser ELSIF
, ELSE IF
ou THEN IF
! Mais pour ces deux derniers, il faudra faire usage de parenthèses comme sur l'exemple ci-dessous :
1 2 3 | Information := (IF Reponse = 'o' THEN 1 ELSIF Reponse = 'n' THEN 0 ELSE 2) ; -- OU Information := (IF Reponse = 'o' THEN 1 ELSE (IF Reponse = 'n' THEN 0 ELSE 2)) ; |
Les expressions CASE
Mais cette importante mise à jour de la norme Ada ne s'arrête pas là. La même possibilité est offerte avec l'instruction CASE
! Voici ce que cela donnerait :
1 2 3 4 | Information := (CASE Reponse IS WHEN 'o' => 1 WHEN 'n' => 0 WHEN OTHERS => 2) ; |
Il est même possible de combiner CASE
et IF
dans une même expression ! Attention toutefois à ne pas vous perdre dans des tests trop compliqués : les expressions sont faites pour condenser le code et pas pour l'alourdir.
N'oubliez pas également qu'au final, vos tests doivent renvoyer la valeur à affecter à votre variable.
Toujours plus complexe
Pour terminer, sachez que si votre variable a déjà été initialisée, il est même possible de l'utiliser au sein même de son expression. Regardez par exemple ce code :
1 2 | Get(x) ; skip_line ; x := (if x>= 0 then x else -x) ; |
L'utilisateur saisit une valeur de x dont on ne connaît pas le signe. La seconde ligne a pour but de la rendre positive : si x est déjà positive ou nulle, on lui affecte sa propre valeur, sinon on lui affecte la valeur -x qui sera nécessairement positive.
Nous avons fait un premier tour des conditions en Ada. L'élément le plus important est la suite d'instruction IF/THEN/ELSE
, mais n'oubliez pas qu'il existe l'instruction CASE
pour simplifier votre code. Avec ces quelques instructions en tête, vos programmes devraient d'ores et déjà prendre un peu de profondeur.
En résumé :
- L'instruction
IF
permet de tester une égalité à la fois (ou une égalité). Pour effectuer plusieurs tests, vous devrez imbriquer plusieursIF
après des instructionsTHEN
ouELSE
. - Pour effectuer un grand nombre d'actions différentes, il vaudra souvent mieux utiliser l'instruction
CASE
. Toutefois, elle ne permettra pas de tester des inégalités. - Une instruction
CASE
doit proposer une action pour toutes les valeurs possibles de la variable testée. Si vous souhaitez effectuer la même action pour tous les cas « inutiles », utilisez l'instructionWHEN OTHERS
.