Capsule : Instructions

Notion d’instruction

Nous avons défini un programme comme étant une séquence d’instructions où chaque instruction est une étape nécessaire à la production du résultat. Chacune d’elles est nécessaires parce qu’elle fait quelque chose, elle a un effet qui dure après son exécution et le résultat des instructions suivantes dépend de cet effet.

Pour un programme écrit dans un langage de programmation, nous allons donc définir une instruction comme étant une construction du langage qui a un effet dans le sens où son exécution change quelque chose, quelque part. Par exemple, après l’exécution de la procédure System.out.println("Veuillez saisir une valeur : ");, le texte passé en paramètre (« Veuillez saisir une valeur : ») apparaît dans la fenêtre du terminal ou la fenêtre Output de NetBeans alors qu’il n’y était pas avant; la procédure println change l’état de la sortie standard. De même, après l’exécution de l’affectation r = a % b;, la valeur de la variable r est le reste de la division de a par b quelque soit la valeur qu’elle pouvait avoir avant; l’affectation change la valeur d’une variable. Pour désigner l’effet d’une instruction, on utilise souvent le terme effet de bord ou side effect en anglais.

Dans un langage de programmation impératif et structuré tel que Java, C#, ou JavaScript, on trouve généralement les instructions suivantes :

  • L’affectation qui permet d’attribuer une valeur ou le résultat d’une opération à une variable.
  • L’appel de procédure qui permet d’exécuter un sous-programme qui a un effet (une procédure), en lui passant éventuellement des valeurs en paramètres (p. ex. écrire une chaîne dans la sortie standard).
  • Des structures de contrôle :
    • Des structures de choix (alternative et choix multiple) qui permettent d’exécuter ou non une séquence d’instruction selon qu’une condition est ou non remplie.
    • Des structures de boucle qui permettent de répéter une séquence d’instructions un certain nombre de fois (boucle définie) ou aussi longtemps qu’une condition est remplie (boucle indéfinie).

L’affectation

L’affectation est une instruction qui permet d’attribuer une valeur à une variable. Si on affecte une valeur à une variable qui avait déjà une valeur, celle-ci est remplacée et définitivement perdue.

En Java et dans beaucoup d’autres langages, le symbole de l’affectation est le signe égal =. Ce signe est trompeur, car une affectation n’indique pas que les deux parties sont égales, elle indique que la valeur de la partie gauche, une variable, sera celle obtenue par l’évaluation de l’expression de la partie droite. L’instruction s’exécute donc en deux temps :

  1. évaluation de l’expression de la partie droite;
  2. attribution de la valeur obtenue à la variable de la partie gauche.

La partie gauche et la partie droite d’une affectation ne sont donc pas interchangeables. La première est toujours le nom de variable à laquelle on veut attribuer une valeur. La seconde est n’importe quelle expression dont le type est compatible avec celui de la variable de la partie gauche.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
...
// Déclaration et initialisation des variables a et b.
double a = 10;
double b = 2
// Déclaration de la variable f.
double f;

// Évalue l’expression a / 2 (10 / 2 = 5) puis attribue 
// cette valeur à la variable a. Avant l’exécution, f
// n’a pas de valeur définie, après l’exécution, la
// valeur de f est 5.
f = a / 2; 

// Évalue l’expression f + b (5 + 2 = 7) puis attribue 
// cette valeur à la variable f. Avant l’exécution, la
// valeur de f est 5, après l’exécution, la valeur de
// f est 7.
f = f + b
...
Fig. 1 – Exemple d’affectation

L’extrait de code de la figure 2 montre une affectation dont l’expression de la partie droite à un type qui n’est pas compatible avec celui de la variable de la partie gauche. En effet, dans ce cas, l’expression est de type double alors que la variable est de type int. Comme il n’est pas possible de convertir un nombre à virgule en un nombre entier sans risquer de perdre des informations (les chiffres après la virgule), Java refuse de le faire sauf si vous fait une conversion de type (type casting) explicite comme le montre la ligne 14.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
...
// Déclaration et initialisation de la variable a.
double a = 10;
// Déclaration de la variable i.
int i;

// C’est affectation n’est pas valide, car le type de 
// l’expression a / 2 est double et une valeur de
// type double ne peut pas être attribuée à une variable
// de type int (types incompatibles).
i = a / 2; 

// Avec une conversion de type explicite (type casting),
// on demande à Java de convertir le type de la valeur de
// l’expression en int avant de l’attribuer à la variable i.
i = (int)(a / 2); 
...
Fig. 2 – Types incompatibles (incompatible types)

L’extrait de code suivant (figure 3) contient une erreur qui met en évidence le fait que l’affectation s’effectue en deux temps. En effet, l’exécution d’une affectation commence par l’évaluation de la partie droite, mais dans à la ligne 8, l’évaluation de l’expression f + a est impossible à cause de la variable f dont la valeur n’est pas définie.

1
2
3
4
5
6
7
8
9
10
11
...
// Déclaration et initialisation de la variable a.
double a = 10;
// Déclaration de la variable f.
double f;

// C’est affectation n’est pas valide parce que la valeur
// de f n’est pas définie et que l’expression f + b ne peut 
// donc pas être évaluée (variable non initialisée).
f = f + a; 
...
Fig. 3 – Variable possiblement non initialisée (variable might not have been initialized)

La variable f a bien été déclarée à la ligne 3, mais aucune valeur ne lui a été affectée lorsque vient le moment d’exécuter la ligne 8. NetBeans nous informe de ce problème à l’aide d’un message d’erreur qui dit que la variable f n’a possiblement pas été initialisée (variable might not have been initialized).

L’appel de procédure

Lorsqu’on utilise un langage de programmation comme Java, C# ou JavaScript, on utilise également une bibliothèque (library) de sous-programmes. Nous reviendrons plus en détail sur la notion de sous-programme lorsque nous étudierons leur réalisation. Pour l’heure, il nous suffit de savoir qu’un sous-programme est un programme (une séquence d’instructions) qui porte un nom dont on peut demander l’exécution (on dit « appeler » (call) ou « invoquer » (invoke) un sous-programme) en lui passant éventuellement des informations.

Vous connaissez déjà plusieurs sous-programmes, dont les procédures print, println et printf que vous utilisez pour écrire des chaînes de caractères dans la sortie standard, et les fonctions nextInt, nextDouble que vous utilisez pour lire des valeurs dans l’entrée standard. Le terme « fonction » désigne un sous-programme qui renvoie une valeur après son exécution; le terme « procédure » désigne, quant à lui, un sous-programme qui ne renvoie pas de valeur et qui a un effet de bord. Dans cette partie, nous allons nous intéresser aux procédures uniquement. Les fonctions seront traitées avec les expressions.

Puisqu’une procédure a un effet de bord, l’appel d’une procédure correspond bien à la définition d’une instruction. En Java, on appelle une procédure en écrivant son nom suivi d’une paire de parenthèses. La plupart des procédures demandent qu’on spécifie la valeur d’un ou plusieurs paramètres. Si l’on prend l’exemple de la procédure print, celle-ci demande qu’on lui passe la chaîne de caractères (le texte) qu’elle doit écrire dans la sortie standard.

Structure de choix

Structure de boucle définie

Structure de boucle indéfinie