Vous êtes sur la page 1sur 9

-- définition d'une procédure et d'une fonction

Tour d'horizon --
des --
with Ada.text_io; use Ada.text_io; -- ignorer pour l'instant
fonctionnalités clefs du langage ADA procedure Exemple2 ; is
Stéphane MARIEL Package int_io is new Ada.Text_Io.integer_io(Integer); use
Int_Io; -- idem
value : integer;
Avant Propos procedure Bar(a: in integer) is
Le langage ADA est un langage à part parmi tous les dialectes informatiques. Défini comme la i: integer := 1;
réponse à un appel d'offre du ministère américain à la défense (DoD), norme ISO, il présente begin
i := 4;
une richesse fonctionnelle étonnante (ceci dès sa première version en end Bar;
1983) tout en mettant en oeuvre des mécanismes stricts garantissant la function Foo(B: in Integer) return integer is
conformité des programmes à l'exécution. I: integer := 3;
Aujourd'hui ce langage peu mis en avant est utilisé dans l'industrie begin
aéronautique et de défense dans le monde entier. return i;
end Foo;
Le nom du langage fut choisi en hommage à Lady Ada Byron, comtesse
begin
de Lovelace, assistante de Babbage et considérée comme le premier bar(Value);
programmeur de l'histoire. Value := foo(4);
put("hello world!"); new_line;
put(value); new_line;
I. Structure d'un programme
La base syntaxique d'ADA est le langage Pascal. Rien d'original en la matière donc. Leend;
langage distingue procédures et fonctions comme il se doit et toute procédure peut être
choisie pour sous-programme principal (en C il s'agit de main). Il faut noter que les fonctions n'acceptent que des paramètres en lecture seule. Ceci afin de
-- mon premier programme ada limiter les effets de bord. Enfin, en ADA, toutes les procédures et fonctions sont
-- hello world ! surchargeables, sous réserve d'avoir des signatures (prototypes) différentes, valeurs par défaut
with text_io; use text_io;
procedure exemple1 is exclues.

begin with ada.text_io;


put("hello world!"); procedure exemple3 is
end; package int_io is new ada.text_io.integer_io(integer);
procedure foo(i : integer) is
begin
Par défaut et contrairement aux langages fondés sur C, les arguments de la ligne de int_io.put(i);
commande ne sont pas associés au sous-programme principal. Il convient pour en disposer end foo;
de faire appel à une bibliothèque spécifique. Ce fonctionnement est compréhensible pour un procedure foo(i : integer; j: integer) is
langage dont la vocation est le plus souvent de réaliser des systèmes embarqués. begin
int_io.put(i);
ada.text_io.put(",");
I.1. Sous-programmes int_io.put(j);
ada.text_io.new_line;
Concernant les sous-programme en général, ADA propose un mécanisme de passage des end;
paramètres indépendant du compilateur. Traditionnellement c'est au contraire aubegin
développeur de choisir entre passage par copie ou par référence. foo(3,4);
Le langage ADA offre une approche différente en proposant de choisir entre un mode enend exemple3;
lecture seul, un mode en écriture seule, ou un mode mixte. La réalité du mode de passage
choisi incombant au seul compilateur, probablement mieux à même de déterminer pour une
architecture donnée la solution la plus efficace.
I.2. Un peu d'exotisme t1 : array (rouge..blanc) of integer;
type mytab is array (couleur'range) of integer;
Le langage ADA prend parfois à contrepied certaines bonnes vieilles habitudes, en matière de t2 : mytab;
syntaxe comme de contraintes. procedure put(a : mytab) is
begin
Utilisation d'attributs ada.text_io.put ("(");
for c in a'range loop
Il s'agit d'un des éléments probablement parmi les plus perturbants à première vue. ADA int_io.put(a(c));
définit un ensemble d'attributs, qui appliqués à des données ou des types, vont permettre if c /= a'last then
d'obtenir des informations souvent élémentaires ou intimement liées à la donnée. ada.text_io.put(", ");
end if;
L'appel à ces attributs, on parle de qualification, se fait au moyen du caractère « ' » end loop;
(apostrophe ou quote). ada.text_io.put(")");
end put;
Ainsi sur un type de données on pourra obtenir la borne inférieure, la précision maximale.begin
Pour les objets il sera possible d'obtenir la classe ou le type. Sur un tableau les différents t2 := ( bleu | vert => 5, others => 3 );
indexes. put(t2);
end exemple5;
En réalité ses attributs sont tous simples, il suffit de les imaginer comme de simples méthodes sous
programme
sous
programme
bloc bloc

appelées non pas avec la notation pointée habituelle mais avec la quote. II. Exceptions
-- un exemple de type enuméré, avec utilisation de la qualification
with Ada.text_io; use Ada.text_io; ADA complète la syntaxe de base du langage par le support des
procedure exemple4 is exceptions. Un support qui pourra paraître simpliste au regard des
type couleur is ( blanc, bleu, jaune, rouge, vert, orange); mécanismes offerts par exemple dans Java. La réalité est qu'un tel
package couleur_io is new ada.Text_io.enumeration_io(couleur); niveau est probablement très suffisant.

ale
use couleur_io;
Le langage propose un type de données : exception. Chacun peut

ion norm
c : couleur := bleu;
naturellement déclarer de nouvelles exceptions (en plus de celles

Exécut
begin définies par défaut). L'exception en ADA s'assimile à un signal
put(c); new_line; nommé, elle ne porte pas d'information additionnelle.
put(Couleur'pred(C)); New_line; Lorsque qu'une exception est déclenchée (on dit levée) le signal se
end exemple4;
propage en remontant la pile des blocs d'instructions puis des sous-
programmes, ceci tant qu'aucun bloc de traitement n'est rencontré.
Au pire, si même le sous-programme principal ne comporte aucun
Les tableaux : intervalles et agrégats bloc pour traiter l'exception, l'exécution du programme est stoppée.
Le bloc de traitement des exceptions peut être vu comme le switch du langage C. Chaque
Contrairement au langage C, un tableau peut être indexé par tout intervalle d'un type discret,exception peut recevoir un traitement dédié, ou un traitement global peut être exécuté pour un
cela inclut donc les types énumérés, les entiers, et les types dérivés. ensemble d'exceptions.
Les bornes de l'intervalle sont librement fixables. L'instruction raise permet de lever une exception explicitement. Les exceptions définies dans le
langage sont elles le plus souvent levées par le runtime.
Enfin il est possible d'utiliser la notion d'agrégat (un équivalent à { ... } en C) pour initialiserA noter que les exceptions sont présentes dans le langage depuis 1983.
un tableau en une seule fois. En ADA l'agrégat est donné entre parenthèses, on peut initialiserwith text_io; use text_io;
les valeurs par position, par nom (notamment pour les index de types énumérés), enfin laprocedure Exemple6 is
clause others permet de donner une valeur par défaut à tous les éléments non encore Monexception : exception;
procedure Foo(I : in Integer := 0) is
initialisés du tableau. begin
with ada.text_io; if I < 0 then
procedure exemple5 is raise Constraint_Error;
type couleur is ( bleu, rouge, vert, jaune , blanc ); elsif I > 10 then
package int_io is new ada.text_io.integer_io(integer); raise Monexception;
end if;
end Foo;
begin with text_io; use text_io;
begin package body ComplexPkg is
Foo(-4); package real_io is new float_io(float); use real_io;
exception procedure Set ( Z: out Complex; A, B : in Float := 0.0) is
when Constraint_Error => begin
put("Ok, il n'y a pas mort d'homme."); new_line; Z.X := A; Z.Y := B;
raise Monexception; end Set;
end; function Getr (Z : in Complex) return Float is
exception begin
when others => return Z.X;
Put("Rah! Mieux vaut en finir"); new_line; end Getr;
end Exemple6; function Geti (Z : in Complex) return Float is
begin
return Z.Y;
end Geti;
III. Modèle de composants function I return Complex is
tmp : complex ;
Au delà des améliorations apportées au langage Pascal, ADA introduit une approche begin
modulaire du développement en permettant la compilation séparée de portions du code. Ces Set ( tmp, 0.0, 1.0);
return Tmp;
différents unités de compilation vont permettre de mettre en oeuvre des approches dites top-
end I;
down et bottom-up. procedure Put(Z: in Complex) is
begin
Parmi les unités de compilation, ADA introduit la notion de Packages. Ces packages vont
Put("["); Put(Z.X); Put(", "); Put(Z.Y); Put("]");
permettre la définition de bibliothèques (approche bottom-up). end Put;
begin -- initialisation optionnelle
III.1. Packages null;
end ComplexPkg;
Les packages ADA sont donc des librairies réutilisables. Chacun dispose d'une spécification et
d'une ou plusieurs implantations.
A ce stade on dispose d'un modèle de composant satisfaisant mais n'offrant aucun niveau de
Cette séparation va permettre de tirer profit des différents modes de développement (top-downprotection des données. Ainsi un type de données défini dans la spécification d'un composant
ou bottom-up). En effet, spécification comme implantation sont des unités de compilation etverra son implantation librement accessible, avec le risque évident de dysfonctionnement à la
sont compilables séparément. On pourra donc compiler un programme principal avant sesmoindre mise à jour.
composants, tester des composants en priorité ou encore développer des implantations de
Pour contrer ces mauvaises pratiques potentielles, ADA complète son modèle composant en
test.
affinant la notion de spécification, désormais partitionnée en deux blocs : une partie publique
L'instruction package est utilisée seule pour définir les spécifications d'une librairie. Pouret une partie privée.
l'implantation on utilisera le couple : package body.
On pourra donc se contenter d'indiquer l'existence d'un type de donnée dans la partie
package ComplexPkg is publique, quand son implantation sera réservée à la partie privée. Pour un tel type de données
type Complex is record aucun accès direct à l'implantation n'est possible. Seules les primitives proposées par le
X,Y : Float := 0.0;
end record; package permettront d'obtenir ou de fixer les valeurs de variables du type concerné.
procedure Set ( Z: out complex; A, B : in Float := 0.0); package ComplexPkg is
function Getr (Z : in Complex) return float; type Complex is private;
function Geti (Z : in Complex) return Float; procedure Set ( Z: out complex; A, B : in Float := 0.0);
function i return complex; function Getr (Z : in Complex) return float;
procedure Put(Z: in Complex); function Geti (Z : in Complex) return Float;
end ComplexPkg; function i return complex;
procedure Put(Z: in Complex); En outre il est possible de définir des extensions privées d'une librairie, soit pour traiter des
private éléments internes, soit encore pour permettre des extensions vendeur (en fonction du matériel
type Complex is record
X,Y : Float := 0.0; par exemple).
end record; with Ada.Numerics;
end ComplexPkg; private package Complexpkg.Internals is
type PolComplex is private;
function Cart2pol(Z: in Complex) return Polcomplex;
Lorsqu'une unité de compilation doit faire appel à un package, l'instruction with est utilisée. private
subtype Positivefloat is Float range 0.0 .. Float'Last;
Elle permet à la fois de disposer d'une visibilité sur les types et sous-programme définis, mais subtype Angle is Float range -Ada.Numerics.PI .. Ada.Numerics.PI;
instruit aussi le compilateur pour les opérations de link futures. On peut imaginer que type Polcomplex is record
l'instruction with équivaut au couple #include, -lXXX du langage C. R : Positivefloat := 0.0;
A : Angle := 0.0;
with ComplexPkg; end record;
procedure exemple7 is end Complexpkg.Internals;
z1, z2: ComplexPkg.complex;
begin
ComplexPkg.set(z1, 6.0, 8.0); Avec ces librairies hiérarchiques il devient possible de faire évoluer des composants sans
ComplexPkg.set(a =>9.0, b =>3.0, z => z2); remettre en cause l'existant et notamment sans devoir procéder à de nouvelles campagnes de
ComplexPkg.put(z2);
end exemple7; tests sur les éléments existants.

Pa ty leu ion

e
IV. Généricité

ag
ra p e rs s

ck
On couple le plus souvent l'instruction with à la clause use. Ceci va importer l'ensemble des

m s ,

pa
èt ,
va nct

re

de
fo
symboles définis dans le package directement le contexte courant. Il devient alors inutile dePour compléter son modèle composant ADA dispose de

s
:

e
èl
od
préfixer les noms de types, variables, sous-programmes par le nom du package. En cas demécanismes permettant la réalisation de composants génériques.

M
conflit, notamment entre deux packages, il suffira de préfixer au cas par cas.
On peut voir un composant générique comme un élément paramétré.
with complexPkg; use complexPkg; Lors de l'utilisation effective on précisera les paramètres et une version
procedure exemple8 is
z1, z2: complex; spécifique du composant sera créée et utilisable. De manière imagée on
begin peut se représenter le composant générique comme un moule qui va
set(z1, 6.0, 8.0); permettre de créer autant de composants que nécessaires.
set(a =>9.0, b =>3.0, z => z2); Nouveau package

put(z2); En règle général un composant générique permettra d'implanter un


end exemple8; algorithme et sera paramétré par un type de données auquel appliquer cet algorithme
(exemple la gestion de piles ou de files d'attentes).
III.2. Librairies hiérarchiques
Le package en tant que tel est un modèle de composant satisfaisant. Cependant, il est apparugeneric
avec l'expérience que les différents niveaux de visibilité offerts étaient trop rigides, avec pour type Item is private;
conséquences recompilations et modifications de code à répétition. with function "+" (A, B : in Item) return Item;
with function "*" (A, B : in Item) return Item;
Pour résoudre ces problèmes, la version 1995 du langage introduit le concept de librairie fille Zero : Item;
sur les packages. Il devient alors possible de créer une arborescence de librairies complétant with procedure put (i : in item);
chacune un noeud de l'arbre. package Matrixpkg is
type Matrix is array (Integer range <>, Integer range <>) of Item;
package Complexpkg.Numerics is function "+"(A, B : in Matrix ) return Matrix;
function "+" ( Z1,Z2 : in Complex) return Complex; function "*"(A, B : in Matrix ) return Matrix;
Function "*" ( Z1,Z2 : in Complex) return Complex; procedure put(m : in matrix);
end Complexpkg.Numerics; end Matrixpkg;
Il convient à chaque fois de bien étudier les paramètres requis par un module générique. Siaffublé d'un attribut supplémentaire, un tag, permettant de déterminer son type.
naturellement un type de donnée est en général requis, le plus souvent il est nécessaire de
Pour étendre effectivement un type, on utilisera le mot clef with en précisant un record
l'accompagner de diverses opérations et des éléments neutres associés.
additionnel. On peut naturellement étendre un objet sans ajouter aucun attribut en indiquant
Le corps d'un module générique ne diffère en rien du corps d'un module classique. Le type deque le record ajouté est vide.
donnée générique est manipulé comme un type standard, à ceci près que seuls l'affectation, leprocedure exemple10 is
test d'égalité et les opérations passés en paramètre sont disponibles. Ce qui est logique type Point is tagged record
puisque rien ne permet de supposer l'existence d'autres opérations sur ce type. X, Y : Float;
end record;
A l'usage, un module générique doit être instancié. Cela revient à créer un module classique à type Circle is new Point with record
partir de son modèle générique et de paramètres. R : Float;
end record;
with Matrixpkg; -- impossible d'utiliser use sur un module générique type Sphere is new Circle with null record;
with text_io; use text_io;
type Box is new Point with record
procedure Exemple9 is
W, H : Float;
package Int_Io is new Integer_Io(Integer); use Int_Io;
end record;
procedure Put2(I :in Integer) is P : Point ;
begin -- petite astuce car notre module attend une fonction c : circle := ( p with 8.0); -- un cercle est un point + un rayon
Put(I); -- à un seul paramètre, or la fonction put livrée par begin
end Put2; -- défaut comporte plusieurs paramètres, par défaut, P := Point(C); -- on peut aussi caster en sens inverse
-- mais plusieurs quand même. end exemple10;
package Int_Matrix is new Matrixpkg(Integer, "+", "*", 0, Put2);
use Int_Matrix; -- use est utilisable sur la version instanciée
A : Matrix( 1..3, 1..2); V.2. Polymorphisme, Class wide programming A
B : Matrix ( 0..1, 2..4);
begin Avec les types étendus on définit une véritable arborescence
A := ( others => ( others => 1 ) ); de types. ADA permet d'accéder en globalité à l'ensemble de Is new Is new
B := ( others => ( others => 3 ) ); ces types. On parle de class wide programming.
A := A + B;
put(a); Pour désigner le type représentant l'ensemble des types B C
end Exemple9; dérivés d'un type racine, on utilise la qualification avec
l'attribut class. Une classe en ADA n'est donc pas un Is new

V. Modèle objet type d'objet, mais plutôt la réunion d'un ensemble de


types dérivés. D
Malgré la richesse de la notion de package, il manquait au langage un modèle objet et plus
précisément le concept d'héritage. Plutôt que d'introduire la notion de class brutalement,Il est ainsi possible de définir des fonctions opérant B'Class A'Class
comme le fait C++, ADA se contente de tirer profit des éléments déjà présents et va préférer sur toute une classe, classe dont certains types
aux classes l'extension de la notion de types. C'est pourquoi on parlera de programmation parpeuvent être encore non définis au moment de la conception de la fonction, et ajoutés
extension. ultérieurement dans des librairies filles.
Avec ce mécanisme il devient possible de sélectionner les méthodes appliquées au plus tard,
V.1. Extension de types au moment de l'exécution, ceci en fonction de la nature effective du paramètre (on parle de
Cette possibilité d'extension va s'appliquer au type record (l'équivalent des structures en C). Enlate binding).
l'absence d'enveloppe pour l'objet (la classe) on va appeler méthodes (ou procédures etwith Text_Io; use Text_Io;
fonctions primitives) les procédures ou fonctions prenant le type étendu en paramètre ou pourwith ada.tags; use ada.tags;
les fonctions retournant ce type. C'est donc sur cet ensemble type plus primitives que va porterwith ada.Integer_Text_Io; use ada.Integer_Text_Io;
procedure exemple11 is
l'héritage.
type Point is tagged record
Pour préciser qu'un type record va pouvoir faire l'objet d'extensions on va utiliser le mot clef X,Y : Float;
end record;
tagged. Le mot tagged est réellement adapté car en fait le type record se retrouve comme
type Circle is new Point with record
R : Float; begin
end record; P := Point(C);
type Rectangle is new Point with record end Exemple12;
Width, Height : Float;
end record;
type object is access point'class; V.4. Types dérivés et package
procedure Dispatch(O : in point'class) is On a vu qu'un package peut cacher l'implantation des types définis dans sa spécification. La
begin
if (O in Circle'Class) then définition détaillée restant alors protégée dans la zone privée. Dans le cas de la
null; -- on devrait faire qquechose programmation par extension, ce fonctionnement permet de définir avec beaucoup de finesse
elsif (O in Rectangle'Class) then le degré de visibilité des types définis.
null;
procedure Exemple13 is
else
package Test1 is
Put_Line("Hum, this " & external_tag(o'tag) & "looks weird to
-- on nous cache meme le fait que t est tagged
me."); -- il nous sera impossible de créer des types
end if; -- dérivés
end Dispatch; type T is private;
I : Integer; private
O : Object;
type T is tagged record X,Y : Float; end record;
begin
end Test1;
Get(I);
case I is package body Test1 is
when 1 => end Test1;
--
O := new Point;
package Test2 is
when 2 =>
-- ici, meme si l'implantation exacte de t est
O := new Circle; -- inconnue, on pourra créer un type dérivé
when others => type T is tagged private;
O := new Rectangle; private
end case; type T is tagged record X,Y : Float; end record;
dispatch(O.all); end Test2;
end exemple11; package body Test2 is
end Test2;
-- on etend donc un type opaque (test2.t) avec de
-- nouveau éléments.
V.3. types abstraits type T2 is new Test2.T with record Z : Float; end record;
-- ce qui est aussi possible dans un package tiers :
Enfin, ADA comme la plupart des langages, offre la possibilité de définir des types et sous- package Test3 is
programmes abstraits, ceux-ci permettent de définir un cadre à respecter et implanter par les type T is new Test2.T with private;
types dérivés. Naturellement ces types et sous-programmes ne sont pas utilisables en tant que private
type T is new Test2.T with record Z: Float; end record;
tels. end Test3;
procedure exemple12 is package body Test3 is
type Object is abstract tagged record end Test3;
X, Y : Float; -- à cela il faudrait ajouter les possibilités propres
end record; -- aux librairies filles.
-- Object n'est pas utilisable en tant que tel begin
-- mais les types dérivés oui. null;
Type Point is new object with null record; end Exemple13;
type Circle is new Point with record
R : Float;
end record;
P : Point ;
C : Circle := ( P with 8.0);
VI. Environnement multitâche intégré La définition d'une tâche en ADA peut être (très grossièrement) comparée à celle déjà détaillée
du package. Chaque tâche va en effet disposer d'une spécification et d'une implantation (le
La prise en compte au sein même du langage du multitâche est une autre originalité d'ADA.corps).
Cet élément clef a d'ailleurs longtemps été mal supporté dans les outils Open Source,
notamment parce que les systèmes sous-jacents (Les Unix et GNU/Linux en particulier) newith text_io; use text_io;
procedure exemple15 is
supportaient pas le multi-threading en natif. task T1;
task t2;
VI.1. Les objets tâches task type Simple;
type Simpleptr is access Simple;
Dans un programme classique il n'existe qu'une tâche, le sous-programme principal. Celui-ci T3 : Simple;
se déroule en exécutant en séquence ses instructions (et celles des sous-programmes appelés). T4 : Simpleptr;
task body T1 is
En ADA il est élémentaire de créer des tâches additionnelles. Le runtime (seul ou avec l'OS) va begin
alors donner l'illusion que toutes ces tâches s'exécutent simultanément en exécutant Put_Line("Hello from t1");
successivement des petits morceaux de chaque tâche (C'est le principe du multitâche, tout end T1;
l'objet du jeu étant alors de correctement réaliser le partage de la ressource CPU). task body T2 is
begin
with text_io; use text_io; Put_Line("Hello from t2");
procedure exemple14 is end T2;
task T1; task body simple is
task body T1 is begin
begin Put_line("hello from simple");
Put("hello from t1"); end simple;
end T1; begin
begin Put_line("hello from main");
Put("hello from main"); T4 := new Simple;
end exemple14; Put_line("Created new simple");
end exemple15;
Excepté dans le cas particulier d'une tâche créée dynamiquement, toutes les tâches voit leur
exécution commencer au begin du bloc où elles ont été déclarées. Cette exécution comporte :
une phase d'élaboration des déclarations (variables, sous-programmes) et l'exécution des
Dans le cas d'une tâche si le corps représente naturellement les instructions qui seront
instructions proprement dites.
exécutées, les spécifications de leur coté vont préciser l'API de la tâche (on parle de points
A noter qu'une tâche peut avoir terminé l'exécution de ses instructions (on dit qu'elle estd'entrée). Cette API décrit les différents appels reconnus par la tâche, appels (qu'on peut
achevée) sans pour autant être terminée. En effet, lorsque plusieurs tâches sont définies aucomparer aux appels système d'un noyau GNU/Linux par exemple) qui serviront à
sein d'un même bloc, la terminaison effective de l'ensemble, tâches + bloc, ne survient quecommuniquer avec elle.
lorsque tous sont achevés. Il faut donc prêter attention aux tâches qui pourraient boucler et ne
En effet en l'absence de points d'entrée une tâche s'exécute dans son environnement
jamais autoriser la terminaison du bloc qui les contient, par exemple une procédure ou une
indépendamment du reste. Cette situation est rarement souhaitée.
fonction.
begin new terminaison
activation
t1
t2
t3 Activation
t4 Execution
Achèvement
VI.2. Le modèle du rendez-vous VI.3. Traitement amélioré des rendez-vous
t1 t2
Les points d'entrée définis sont donc des moyens de En utilisant l'instruction accept dans une boucle on peut facilement traiter les rendez-vous en
communiquer avec une tâche, mais selon quel protocole? ADA séquence, créant une véritable tâche serveur. Cependant cela ne permet pas de répondre à
adopte le modèle du rendez-vous (le même que celui de la vie des rendez-vous différents. Pour cela ADA dispose de l'instruction select.
courante). Il s'agit d'un modèle avec synchronisation.
Select permet d'attendre des rendez-vous différents. L'instruction est bloquante (comme accept)
Du coté de l'appelant (on peut dire client), on doit attendre que t2.hello tant qu'aucun appel n'est en attente. Lorsqu'un rendez-vous est demandé, l'instruction accept

Accept hello
la tâche appelée (tâche serveur) soit prête à traiter l'appel. correspondante est utilisée. En cas de demandes multiples, un rendez-vous est choisi
Pendant le traitement, l'appelant est suspendu. Il reprend le aléatoirement. En plaçant select au sein d'une boucle les demandes de rendez-vous ignorés
déroulement de ses instructions une fois l'appel terminé. seront traitées lors d'un prochain tour de boucle.
Coté appelé (tâche serveur), à supposer que l'on soit en attente
t1.bye with Text_Io; use Text_Io;

Accept bye
with Ada.Numerics.Discrete_Random;
d'appel on reste bloqué tant qu'aucun appel n'est reçu. Lorsqu'un procedure exemple17 is
appel arrive, les instructions associées à ce point d'entrée sont -- on veut des valeurs entre 0 et 10
exécutées. Ceci fait, les deux tâches reprennent le déroulement -- il suffit de definir le sous-type adhoc
de leurs instructions, chacune de leur coté. subtype Smalldelay is Integer range 0 .. 10;
-- d'instancier le package fournissant un générateur
Dans la pratique, pour appeler une tâche on utilise la notation -- de nombres aléatoires pour notre type à nous
pointée : <nom de tâche>.<nom du point d'entrée> ( <paramètres éventuels>); package Random_Smalldelay is new Ada.Numerics.Discrete_Random
(Smalldelay);
Coté tâche appelée, ou serveur, on utilise l'instruction accept use Random_Smalldelay;
pour attendre un appel. Ce sont les spécifications de ce bloc qui gen : generator;
package int_io is new integer_io(integer); use int_io;
sont reprises dans les spécifications de la tâche serveur en utilisant l'instruction entry. task Server is
with text_io; use text_io; -- le serveur répond à 3 appels entrant
procedure exemple16 is entry Init(I : in Integer);
task T1 is entry Set(I : in Integer);
entry Bye; entry Get(I : out Integer);
end T1; end Server;
task T2 is -- le client à aucun
entry Hello; task type Client;
end T2; Clients : array ( 1..10) of Client;
task body T1 is task body Server is
begin local : integer;
T2.Hello; begin
accept Bye do accept Init(I : in Integer) do
Put_Line("T2 a eu notre bonjour et nous dit au revoir"); local := i;
end Bye; end Init;
end T1; put_line("le server est initialisé");
task body T2 is loop
begin select
accept Hello do accept Set(I: in Integer) do
Put_Line("T1 nous dit bonjour, mais on ne veut pas parler"); Local := I;
end Hello; end Set;
T1.Bye; or
end T2; accept Get(I : out Integer) do
begin I := Local;
null; end Get;
end exemple16; or
terminate;
end select;
end loop; begin
end Server; Put("hello from simple");
task body Client is end simple;
s : integer := 5; t1, t2 : simple;
begin begin
put_line("je suis un client"); Put("hello from main");
for I in 1 .. 10 loop end exemple18;
if (I mod 2) = 0 then
Server.Get(S);
delay duration(random(gen));
Put("lecture de la variable :"); Enfin, il est possible de définir un type pointeur sur le type tâche précédemment défini. Avec
Put(s); dans ce cas l'opportunité de créer de nouvelles tâches dynamiquement au coeur d'un bloc
New_Line; d'instructions.
else
Server.Set(S + 10 - I);
delay duration(random(gen)); VII. Distribution des tâches
Put_Line ("ecriture de la variable"); A suivre.
end if ;
delay 0.0;
end loop;
end Client;

begin
delay 2.0;
Put_Line("Initialisation server");
server.init(5);
Put_Line("programme principal");

end exemple17;

Avec select une tâche serveur va donc pouvoir répondre à de multiples rendez-vous. Mais
l'instruction select recèle de nombreux raffinements :
• la possibilité de sortir de la phase d'attente, soit sur timeout (clause delay) ou lorsqu'il n'est
plus possible pour la tâche d'être appelée (clause terminate, qui achève la tâche),
• la possibilité de conditionner (on parle de gardes) chaque bloc accept à une expression
booléenne.

VI.4. Types tâches et création dynamique


Jusqu'à présent les tâches sont créées une à une. Cependant ADA permet de définir des types
d'objet tâches.
Dans ce cas, on dispose de types au sens classique du terme, il est alors possible de créer des
variables tâches unitaires, ou sous forme de tableau.
with text_io; use text_io;
procedure exemple18 is
task type simple;
task body simple is