Le but de la programmation n'est pas seulement de faire des programmes qui marchent. Ils doivent également être lisibles, faciles à mettre à jour et plus concis.
C'est essentiellement à cela que servent les sous-programmes.
Ecrire du code à l'aide de sous-programme est avant tout une manière de programmer : au lieu de concevoir un programme en un seul bloc, on le découpe en plusieurs parties aussi indépendantes que possibles. Chacune de ces parties porte un nom: ce sont les sous-programmes.
Bien entendu, cette manière de programmer n'est pas obligatoire. On peut très bien programmer sans jamais écrire de sous-programmes, mais cela donne des programmes très longs, peu lisibles et difficiles à mettre à jour.
Par analogie, on pourrait comparer ceci au découpage d'une entreprise en plusieurs services. Chaque service ayant un rôle particulier à jouer dans l'entreprise. De même, on peut concevoir un programme en plusieurs sous-programmes réalisant chacun un traitement particulier.
Le PC est une autre analogie intéressante. Dans un PC chaque partie est facilement remplacable par une autre: vous pouvez remplacer l'écran par un autre écran, la carte son par une autre carte son, le clavier par un autre clavier, etc ... Cette possiblité de remplacer chaque partie par une autre partie compatible est possible grâce à la conception modulaire du PC. Un programme sans sous-programme est comme un PC en un seul bloc: impossible d'interchanger les parties.
Dans le premier cours nous avons déjà vus quelques sous-programmes.
Reprenons l'exemple du projet Addition.
Lorsque l'utilisateur clique sur le bouton, la procédure évènementielle BoutonAdditionnerClick est automatiquement exécutée.
Cette procédure évènementielle est un exemple de sous-programme.
Une autre catégorie de sous-programmes que j'appelerais sous-programmes non évènementiels, ne peuvent s'exécuter que s'il existe quelque part une instruction spéciale: l'appel de sous-programme.
De telles instructions figurent à l'intérieur de la procédure BoutonAdditionnerClick:
procedure TForm1.BoutonAdditionnerClick(Sender: TObject); begin LireEntier (x,zoneTexteX); LireEntier (y,ZoneTexteY); somme := x + y; AfficherEntier (somme, ZoneTexteSomme); end;
LireEntier et AfficherEntier sont en fait des sous-programmes (non évènementiels). Dans cet exemple, les trois instructions en rouge sont des appels de sous-programme. LireEntier est donc appelé deux fois et AfficherEntier, une fois.
Par contre, le code du projet Addition ne contient aucun appel du sous-programme BoutonAdditionnerClick. Comme il s'agit d'un sous-programme évènementiel, son exécution sera déclenchée par un évènement. En l'occurence, un clic sur le bouton Additionner.
Evidemment, l'exécution des sous-programmes LireEntier et AfficherEntier est également déclenché, mais de manière indirecte. Si BoutonAdditionClick ne contenait pas des instructions d'appels de ces procédures, elles ne seraient jamais exécutées !
Un projet Lazarus est généralement composé de plusieurs fichiers sources Pascal appelés unités.
Dans le projet Addition par exemple, nous avons deux modules:
De manière générale, chaque formulaire est associé à une unité contenant les procédures évènementielles. C'est l'unité qui gère l'interface graphique du programme. Dans notre exemple, c'est l'unité UnitAddition. Mais il peut y avoir plusieurs autres unités contenant le code de sous-programmes non évènementiels. Dans notre exemple, il n'y a qu'une seule unité de ce type. C'est l'unité entrees_sorties.
Jetons un oeil dans le fichier entrees_sorties. On y trouve, par exemple le code du sous-programme AfficherEntier que voici:
procedure AfficherEntier(x: integer;c:TObject); begin if c is TEdit then (c as TEdit).Text:=IntToStr(x) else if c is TListBox then (c as TListBox).Items.Add(IntToStr(x)) else begin ShowMessage('Erreur dans la fonction Afficher: type du 2ème paramètre non valide'); end; end;
Pour l'instant, vous ne comprenez pas grand chose à ce code, car il fait appel à plein de notions que vous n'avez pas encore vues (structures de contrôles, programmation objet). Notez simplement que la première ligne commence par le mot clé procedure, suivi du nom du sous-programme. Cela signifie que le sous-programme appartient à la catégorie des procédures.
A droite du nom de la procédure, on trouve les paramètres. Dans cet exemple, il y a deux paramètres : x de type integer et c de type TObject.
Toute la première ligne du sous-programme constitue l'entête: elle contient donc le nom du sous-programme et ses éventuels paramètres. Tout ce qui suit est le corps du sous-programme. A l'intérieur du corps du sous-programme figurent donc les instructions que le sous-programme doit exécuter.
Les paramètres sont les données d'un sous-programme. Dans le cas de la procédure AfficherEntier, x est le nombre à afficher et c le composant de l'interface graphique (zone de texte ou zone de liste) dans lequel on souhaite afficher x.
Nous reviendrons plus en détail sur cette notion de paramètres. Pour l'instant, sachez que tout sous-programme peut avoir des paramètres ou ne pas en avoir.
D'autres sous-programmes du fichier commencent par le mot clé function. Ce sont les fonctions. C'est par exemple le cas du sous-programme ZoneDeTexteVide:
function ZoneDeTexteVide (zt: TEdit) : boolean; begin ZoneDeTexteVide := zt.Text = ''; end;
Nous avons donc deux catégories de sous-programmes: les procédures et les fonctions. Les différences entre ces deux catégories seront vues dans la suite du cours.