Vous êtes sur la page 1sur 47

I.U.T.

Aix Dpartement gnie informatique

Gnie logiciel
1er trimestre 2001/2002 (semaines 5 6)

Cours Ada (suite)

Polycopi tudiants pour le cours deuxime partie (cours 6 9)

Daniel Feneuille

Nom tudiant :

2 Cours 6 Ada les articles (2 heures)

Thme : le type article.


Le type article (comme le type tableau) est un type composite . Un article est une structure de donnes qui possde des composants appels champs ou lments. Mais la diffrence des tableaux, les articles (record en Ada) peuvent contenir des lments de types diffrents . Cest l leur principal intrt. Comme pour les tableaux on peut distinguer (classification) : les types articles contraints. les types articles non contraints (appels aussi articles mutants) mais il faut ajouter les types articles tiquets (tagged). Nous examinerons successivement dans ce cours n6 les deux premiers. Les types tiquets seront vus au moment de ltude des objets et des classes (cours n10).

Les types articles contraints. Description d'un type article.


Pour dfinir un type article il suffit d'numrer les diffrents composants, grce des champs, entre les mots rservs record et end record. Ces champs vont caractriser les lments des objets instancis de l'article. Exemples (dfinition de deux types articles) : type T_UNE_PERSONNE is record NOM : STRING(1 .. 20); -- 3 champs PRENOM : STRING(1 .. 15); AGE : NATURAL := 0; end record; type T_POINT_ECRAN record X, Y : VISIBLE : COULEUR : end record; is NATURAL; -- attention : 4 champs BOOLEAN := TRUE; T_COULEUR;

La dclaration des variables (ou instanciation) se fait de faon classique : POINT_HAUT, POINT_BAS : T_POINT_ECRAN; PAPY, MOUGEOT : T_UNE_PERSONNE;

Les oprations associes aux types articles.


Un type article est un type affectation (sauf si un champ est limited). Type affectation signifie, rappelonsle, que : l'affectation, l'galit et la non galit sont dfinies et cest tout a priori. Exemples (dutilisation globale) : if POINT_HAUT = POINT_BAS then ....... end if; PAPY := MOUGEOT; sont des instructions valides.

D. Feneuille I.U.T. Aix 2001 (cours n 6 fichier COURS6.DOC) 03/04/01

3 Attribut associ aux articles.


On retiendra l'attribut CONSTRAINED qui indique si l'objet est contraint ou non. La rponse est videmment de type boolen. Voir le fichier attribut1.doc (dans le CDRom) pour plus de dtail.

Les valeurs par dfaut.


Le type article est le seul type dont les lments peuvent possder des valeurs initiales par dfaut. Ces valeurs sont seulement prises en compte si dans la dclaration de l'objet aucune initialisation n'est spcifie. Dans l'exemple de type T_UNE_PERSONNE, le champ AGE a une valeur par dfaut (ici la valeur nulle). Un autre exemple (bien connu?) : type T_COMPLEXE is record RE : FLOAT := 0.0; -- partie relle IM : FLOAT := 0.0; -- partie imaginaire end record; Z : T_COMPLEXE;

la dclaration du complexe Z ci-dessus implique (par dfaut) : Z.RE = 0.0 et Z.IM = 0.0 Autre dclaration : B : T_COMPLEXE := (1.0,-1.0); -- initialisation par agrgat!

Accs un champ.
L'accs aux composants d'un objet article se fait par la notation pointe. On slectionne ainsi un composant de l'article. On ne peut plus utiliser dindice comme avec les tableaux (videmment !). Exemple : type is (JANVIER, FEVRIER, MARS, AVRIL, MAI, JUIN, JUILLET, AOUT, SEPTEMBRE, OCTOBRE, NOVEMBRE, DECEMBRE); type T_JOUR is range 1..31; type T_ANNEE is range 1_000..2_500 ; type T_DATE is record JOUR : T_JOUR MOIS : T_MOIS AN : T_ANNEE end record; T_MOIS

:= 31; := DECEMBRE; := 2000;

DEMAIN, AUJOURD_HUI, HIER

T_DATE;

Les trois dates sont initialises au 31 DECEMBRE 2000. Dernier jour du sicle ! Notez le. Mais ceci est une vieille histoire ! DEMAIN.JOUR DEMAIN.MOIS DEMAIN.AN Qui quivaut := := := 1; JANVIER; 2001;

DEMAIN := (1,JANVIER,2001); -- agrgat

sont des instructions d'affectation des champs. Si on modifie lobjet en entier (cest le cas ci-dessus en 3 instructions) on peut le faire en une seule instruction (globalement) avec un agrgat. Voir plus loin pour plus de dtail.

D. Feneuille I.U.T. Aix 2001 (cours n 6 fichier COURS6.DOC) 03/04/01

4
De mme avec : X : T_COMPLEXE; -- a priori X = (0.0 , 0.0) on peut crire : X.RE X.IM

:= :=

30.1 ; 25.7 ; -- ou X := (30.1,25.7) ;

Soit un type article avec des champs de type tableau (qui doivent tre contraints) ou eux-mmes de type article. type T_PERSONNE is record NOM PRENOM AGE DATE_DE_NAISSANCE end record; Instanciation : ANDRE, PIERRE

: : : :

STRING(1..10); -- tableau contraint STRING(1..10); -- tableau contraint NATURAL := 0 ; -- valeur par dfaut T_DATE; -- article champ darticle

T_PERSONNE;

Les affectations suivantes : ANDRE.NOM(2) := PIERRE.DATE_DE_NAISSANCE.MOIS := DEMAIN.JOUR := PIERRE.DATE_DE_NAISSANCE.JOUR := sont valides.

'A'; JUILLET; T_JOUR'SUCC(AUJOURD_HUI.JOUR); HIER.JOUR;

Les agrgats d'articles.


L'agrgat permet de construire une valeur de type article, en donnant une valeur chaque champ en une seule instruction (gain de temps et surtout grande lisibilit !). Les rgles d'association sont identiques celles des agrgats de tableaux (en particulier tous les champs doivent tre initialiss ). Bonne rvision ! Association par position. (23, AVRIL, 1988); -- une date ("Durand ","Andr ",40,(30,JANVIER,1989)); (30.1,25.7); -un nombre complexe

DEMAIN := ANDRE := X :=

Association nominative. (AN => 1980, JOUR => 26, MOIS => JUILLET); (DATE_DE_NAISSANCE => (20,JUIN,1962), AGE => NOM => "Dupont ",PRENOM => "Andr

DEMAIN := ANDRE :=

39, ");

Association mixte (attention ceci nexistait pas pour les agrgats de tableau). := := (23, AN => 1988, MOIS => DECEMBRE); ("Dupond ","Andr ", DATE_DE_NAISSANCE => AUJOURD_HUI, AGE => 20);

DEMAIN ANDRE

Le type article comme paramtre dun sous -programme.


Exemple : criture dune fonction qui effectue l'addition de deux complexes. function ADD_COMPLEXE(Z1,Z2 : in T_COMPLEXE) return begin return (Z1.RE + Z2.RE, Z1.IM + Z2.IM); end ADD_COMPLEXE; T_COMPLEXE is

D. Feneuille I.U.T. Aix 2001 (cours n 6 fichier COURS6.DOC) 03/04/01

5
Utilisation de cette fonction : Z := ADD_COMPLEXE (COMPLEXE1, COMPLEXE2);

On peut galement surcharger l'oprateur "+" ce qui est bien plus agrable. function "+" (Z1, Z2 : in T_COMPLEXE) return begin return (Z1.RE + Z2.RE , Z1.IM + Z2.IM); end; L'utilisation peut se faire par : Z := "+" (COMPLEXE1,COMPLEXE2); ou mieux encore en utilisant pleinement la surcharge du + (oprateur binaire) : Z := COMPLEXE1 + COMPLEXE2; -- trs lisible ! T_COMPLEXE is

Les types articles partie variante


Une dclaration de type partie variante contient, aprs l'identificateur, une partie discriminante (c'est une liste de paramtres formels). De faon abstraite on a le schma : type T_NOM(PARAMETRE : TYPE_DU_PARAMETRE{:= valeur_par_dfaut}) is record -- partie fixe ici absente mais champs stables possibles; {case PARAMETRE is when valeur_1 => -- champs_variants_1 when valeur_2 => -- champs_variants_2 when others => -- autres champs end case;} end record;

La marque entre { et } indique une dclaration optionnelle. La valeur par dfaut du discriminant paramtre sera vue plus loin (il sagira alors dun type article non contraint). Exemple : type T_SEXE

is

(MASCULIN, FEMININ, AUTRE); -- AUTRE ? no comment!

type T_PERSONNE (LE_SEXE : T_SEXE) is record NOM : STRING(1 .. 10); -- partie fixe PRENOM : STRING(1 .. 10); AGE : NATURAL := 0; case LE_SEXE is -- partie variante when MASCULIN => CONSCRIT : BOOLEAN ; QUAND : T_DATE; when FEMININ => NOM_DE_JEUNE_FILLE : STRING(1..10); when AUTRE => null; end case; end record; Le mot rserv null indique qu'il n'y a pas de champ associ ce cas. Dans cet exemple il y a des champs "stables" (partie fixe) et une seule partie variante (case end case). On verra des cas o il ny aura pas de partie fixe et une partie variante, mais aussi (malgr un discriminant) pas de partie variante et une partie fixe ! Un discriminant est un champ particulier accessible par la notation pointe en lecture seule (cest--dire en consultation, aucune modification du discriminant dun article contraint nest possible).

D. Feneuille I.U.T. Aix 2001 (cours n 6 fichier COURS6.DOC) 03/04/01

6
Tout discriminant doit tre de type discret. La dclaration d'un objet de type article non contraint se fait en associant une valeur a priori un discriminant (voir plus loin bis !). Cest ce signe qui diffrencie le type article non contraint du type article contraint (ce dernier na pas de valeur initiale pour tout discriminant). Exemples de dclaration dobjet darticle contraint : LUI : T_PERSONNE (MASCULIN); ELLE : T_PERSONNE (FEMININ); DRAG : T_PERSONNE (AUTRE); -- no comment bis! avec la variable LUI on a les champs possibles suivants : LUI.LE_SEXE (en consultation seulement avec if, case etc.. par exemple). LUI.NOM, LUI.PRENOM, LUI.AGE (en consultation et/ou en modification). LUI.CONSCRIT, LUI.QUAND (en consultation et/ou en modification). avec la variable ELLE on a les champs suivants : ELLE.LE_SEXE (en consultation seulement). ELLE.NOM, ELLE.PRENOM, ELLE.AGE (en consultation et/ou en modification). ELLE.NOM_DE_JEUNE_FILLE (en consultation et/ou en modification). avec la variable DRAG on a les champs possibles suivants : DRAG.LE_SEXE (en consultation seulement). DRAG.NOM, DRAG.PRENOM, DRAG.AGE (en consultation et/ou en modification). Comme pour les types discrets, rels ou tableaux, il est possible de dclarer des sous-types de type article. Par exemple : subtype MACHO : T_MEC T_MEC; is T_PERSONNE (MASCULIN);

avec la variable MACHO on a videmment les champs possibles suivants : MACHO.LE_SEXE (en consultation seulement rappel !). MACHO.NOM, MACHO.PRENOM, MACHO.AGE (en consultation et/ou en modification). MACHO.CONSCRIT, MACHO.QUAND (en consultation et/ou en modification).

Utilisation du discriminant.
Le discriminant peut tre utilis de plusieurs faons : Pour tablir une contrainte d'indice sur un composant de type tableau. T_VECTEUR T_MATRICE is is array array (POSITIVE range <>) of FLOAT; (INTEGER range <>, INTEGER range <>) of FLOAT;

type type

Il est possible de dfinir des types tableaux contraints qui peuvent changer de taille linstanciation. Dans ce cas l, il n'y a pas de champs variants. Pas de case mais .... un discriminant ! Attention ! type T_MAT_CARREE record LE_CARRE : end record; (COTE : POSITIVE) is

T_MATRICE(1..COTE, 1..COTE);

D. Feneuille I.U.T. Aix 2001 (cours n 6 fichier COURS6.DOC) 03/04/01

7
type T_TAB_REELS (L : POSITIVE) record VALEUR : T_VECTEUR(1..L); end record; is

type T_NOM (L : POSITIVE) is - intressant ? voire ! revoir ! record LE_NOM : STRING (1..L); end record; Instanciation : on dclare des objets de ce type en fixant la taille effective : TAB MAT NOM : : : T_TAB_REELS (10); -T_MAT_CARREE (20); -T_NOM (20); -un tableau de 10 rels une matrice 20*20 une chane de 20 caractres

Pour choisir la valeur pour la partie variante de l'article. T_REELS is array (POSITIVE range <>) of FLOAT; T_ENTIERS is array (POSITIVE range <>) of INTEGER;

type type

type T_VECT (REEL : BOOLEAN;L : POSITIVE) is -- il y a 2 discriminants! record case REEL is when FALSE => V_ENT : T_ENTIERS (1..L); when TRUE => V_REE : T_REELS (1..L); end case; end record; Nous avons dfini un type qui sera instanci soit par un tableau de FLOAT, soit par un tableau de INTEGER. TAB_ENT : TAB_REL : T_VECT(FALSE,80); T_VECT(TRUE,80); -- 80 entiers -- 80 rels

Mais cette utilisation n'est pas lisible ! Que pensez vous de celle-ci : type T_NATURE is (ENTIER, REEL); type T_VECT (ELEM : T_NATURE ; L : POSITIVE) is record case ELEM is when ENTIER => V_ENT : T_ENTIERS (1..L); when REEL => V_REE : T_REELS (1..L); end case ; end record; et la dclaration : TAB_ENT : TAB_REL : T_VECT(ENTIER,80); T_VECT(REEL,80);

Un peu plus lisible? Oui ! Bien programmer c'est aussi tre clair !

D. Feneuille I.U.T. Aix 2001 (cours n 6 fichier COURS6.DOC) 03/04/01

8 Les types articles non contraints (concept important) :


Si on veut crer des objets non contraints (avec partie variante dynamique), c'est--dire des objets dont la structure n'est pas fige, la dclaration du type article avec discriminant(s) doit comporter une valeur par dfaut pour un discriminant au moins. De cette faon l'objet n'est pas contraint par une valeur sa dclaration. L'objet dclar a la structure par dfaut. Cette structure peut ensuite tre modifie, mais le changement de la valeur du discriminant ne pouvant se faire que par affectation globale (discriminant + champs). On peut reprendre lexemple du type T_PERSONNE prcdent (page 4). Le rendre non contraint consiste le dclarer ainsi : type T_SEXE is (MASCULIN, FEMININ, AUTRE); Nouveau ! discriminant + affectation

type T_PERSONNE (LE_SEXE : T_SEXE := AUTRE) is -- valeur par dfaut record NOM : STRING(1 .. 10); -- partie fixe PRENOM : STRING(1 .. 10); AGE : NATURAL := 0; case LE_SEXE is -- partie variante when MASCULIN => CONSCRIT : BOOLEAN ; QUAND : T_DATE; when FEMININ => NOM_DE_JEUNE_FILLE : STRING(1..10); when AUTRE => null; end case; end record; Il y a peu de diffrence : seule linitialisation du discriminant LE_SEXE (ici AUTRE mais peu importe !) marque la nature de type non contraint pour ce nouveau type T_PERSONNE. Une variable dclare de type T_PERSONNE mais sans contrainte est par nature non fige (elle peut changer en cours de programmation). On parlera de mutant . Ainsi : HERMA : T_PERSONNE; -- pas de valeur entre parenthse non contraint Une variable dclare de type T_PERSONNE mais avec une contrainte est dfinitivement type sans volution possible. Exemples (on retrouve les mmes que page 5) : UN_MEC UNE_FILLE DRAG : T_PERSONNE (MASCULIN); : T_PERSONNE (FEMININ); : T_PERSONNE (AUTRE);

Non mutants !

On ne peut pas crire (videmment) : UN_MEC.NOM_DE_JEUNE_FILLE := Augusta ; Pour ces trois instanciations il ny a rien de chang par rapport au type article contraint et cest normal car on avait la possibilit de ne pas contraindre la dclaration mais on a contraint quand mme ! Par contre lobjet HERMA a t dclar de nature AUTRE a priori (en labsence de contrainte cest linitialisation par dfaut). Il pourra changer de nature en cours dalgorithme ! Cette mutation ne pourra tre quobtenue que par affectation globale (avec une variable contrainte ou non ou avec un agrgat). HERMA := UN_MEC; -- HERMA devient masculin avec tous ces attributs1 ou HERMA := (FEMININ, Lovelace , Ada ,22, Byron ); -- devient fminin

au propre comme au figur! (gag !). D. Feneuille I.U.T. Aix 2001 (cours n 6 fichier COURS6.DOC) 03/04/01

9
On ne peut pas changer seulement le discriminant sans changer lensemble de la structure et cest assez comprhensible. On peut par contre toujours consulter le discriminant pour savoir o on en est et, bien sr, on peut changer isolment un champ particulier mais cohrent avec la structure ! HERMA.LE_SEXE := FEMININ; -- interdit (comme pour les contraints!) case HERMA.LE_SEXE is consulter cest possible when MASCULIN => ........; when FEMININ => .......; when AUTRE => .......; end case; Si la structure du type mutant "contient" un tableau, sa taille pourra varier dynamiquement en cours dalgorithme. Cest le cas des T_CHAINE exemple assez intressant (consultable en partie commune) et assez analogue aux chanes de caractres variables comme les Bounded_String. type T_CHAINE (L : NATURAL := record CHAINE : STRING (1..L); end record; 0) is

EVOLU : T_CHAINE; -- objet article non contraint taille 0 a priori FIGEE : T_CHAINE(20);-- objet article contraint (de taille 20) EVOLU := FIGEE; -- EVOLU.CHAINE possde maintenant 20 lments. Ou encore EVOLU := (5, Merci ); puis EVOLU := (0, ); -- EVOLU redevient chane vide Attention : FIGEE := EVOLU; -- pas toujours possible De faon gnrale il est peu recommand de mler types contraints et types non contraints. Remarques : Avec le paquetage P_CHAINES ralisant le type T_CHAINE le type est dclar priv (voir les spcifications) et donc la structure nest pas connue lutilisateur. Les exemples daffectation par agrgat ci-dessus ne sont pas valables dans un programme utilisateur ! A revoir. De trs nombreux TD et TP vont permettre de se familiariser avec les articles mutants. (voir TD-TP polynme)

Notez la diffrence !

Types polymorphes, types mutables


(selon une terminologie du groupe Ada-France) Les types avec discriminants qui ne possdent pas de valeur par dfaut sont appels types polymorphes . Les objets instancier peuvent prendre plusieurs formes (elle est fixe linstanciation) mais ils restent incompatibles entre eux. On parle aussi de types paramtrables. Les types avec discriminants qui possdent au moins une valeur par dfaut (donc tous en possdent !) sont appels types mutables . Les diffrentes formes possibles sont compatibles.

D. Feneuille I.U.T. Aix 2001 (cours n 6 fichier COURS6.DOC) 03/04/01

Cours 7 Ada les paquetages (2 heures) Thme : les paquetages.


Avertissement : La notion de paquetage a dj t, dans les premiers TD et TP (algorithmique ou programmation), utilise avec plus ou moins de rigueur (on a surtout parl de ressources ). Il est venu le temps dapprofondir et de structurer cette notion. On verra dabord des notions simples (quoique fortes !) puis ensuite les notions de hirarchie de paquetages (pre - fils) trs importantes depuis la nouvelle norme. Introduction, gnralits, etc. (bref tout ce qui faut savoir et retenir) : Dans les chapitres prcdents nous avons crit des sous-programmes (procdures et fonctions). Les procdures sans paramtres pouvant donner lieu un programme excutable (c'est--dire un programme appelable partir du systme d'exploitation). Dans ces sous-programmes nous avons dcrit des types, des variables, d'autres sous-programmes, qui sont ncessaires notre sous-programme. Un certain nombre de ces descriptions reviennent frquemment dans des applications diffrentes. Il serait donc intressant de disposer d'une mthode pour rutiliser ces dclarations dj crites . La mthode consiste regrouper un certain nombre de dclarations dans une entit (paquet ou module) et de travailler avec ce "paquet", charge pour le compilateur de vrifier que le paquet existe, qu'il est jour, que les dclarations que l'on utilise (on dit "importer") existent et qu'elles sont compatibles avec l'usage que l'on en fait. Cette approche dpasse le concept de bote outils que nous avons dj utilis en TP de programmation. On parle aussi de module (mme si ce concept revt encore des aspects plus compliqus que notre description sommaire). Cette notion de module dans le langage Ada est supporte par le paquetage. Ces modules, compils sparment, permettent l'utilisateur de se crer un environnement riche en les accumulant dans des bibliothques . Un paquetage est une collection d'entits et de ressources logiques. Il permet de regrouper dans une mme unit de programme des dclarations : de constantes, de types, d'objets, de sous-programmes et le code d'initialisation de ces objets. Le lecteur habitu aux units en Turbo-Pascal ne sera pas dpays (mais le paquetage Ada est bien plus qu'une unit du Turbo-Pascal). Le langage Java a repris le concept de paquetage (avec des nuances par rapport aux paquetages Ada). On verra ainsi un peu plus loin comment utiliser un paquetage pour raliser un type abstrait de donnes (T.A.D.). Puis plus tard on passera la programmation avec les objets vrais que permet la nouvelle version de Ada depuis 1995 (voir surtout le cours n10). Ada permet aussi d'encapsuler un ensemble d'informations et d'empcher leur accs directement. Ce qui veut dire qu'il permet de dfinir deux parties , dune part spcification donc visibilit avec l'extrieur et dautre part implmentation (ou ralisation) donc dtails cachs et inaccessibles lutilisateur. Description, structure, usage : Comme les sous-programmes, un paquetage comprend deux parties : La partie spcifications (dclaration ou profil). La partie corps ou body (implmentation ou ralisation).

G. BOOCH1 dans sa mthode de conception oriente objet (C.O.O.) indique que la spcification sert capter la smantique statique de chaque objet ou classe d'objets et sert d'interface entre les "clients de l'objet" et l'objet lui-mme. Ceci sera vu dans le cours n10 cours approfondi . La spcification constitue l'interface entre le paquetage et l'environnement. Elle est vue comme un contrat entre le ralisateur du paquetage et les utilisateurs du paquetage. Le corps ralise la mise en uvre des ressources dfinies dans la partie spcifications. Il permet d'implmenter chaque objet ou classes d'objets en faisant le choix d'une reprsentation adapte. Il est possible de distinguer deux usages des paquetages :

Grady BOOCH : Ingnierie du logiciel avec Ada chez InterEdition (en bibliothque).

2
le paquetage est dclar l'intrieur de l'unit qui l'utilise. Le corps peut cependant tre compil sparment (indication separate ). Cette pratique est assez peu utilise. le paquetage est compil sparment, et import l'aide de la clause with. Le paquetage est alors rutilisable dans un autre contexte (cas le plus frquent).

Exemple simple et connu 2: Supposons que vous avez dj ralis, dans un programme test par ailleurs, un ensemble de sousprogrammes permettant de travailler avec des nombres comp lexes. Il y a, dune part la dclaration du type T_COMPLEXE puis la dfinition (dclaration et ralisation) des sous-programmes (comme +, -, etc.). La rutilisation de ce travail par un autre programme peut se faire par du copier coller (ah les b ufs !) ou videmment plus intelligemment avec le paquetage. La premire partie (spcifications) peut ressembler cela : package P_COMPLEXE is type T_NOMBRE_COMPLEXE is -- dfinition du type et ses composants record PARTIE_REELLE : FLOAT; PARTIE_IMAGINAIRE : FLOAT; end record; -- quelques outils ou oprateurs (on parle aussi de mthodes) function "+" (C1,C2 : T_NOMBRE_COMPLEXE) return T_NOMBRE_COMPLEXE; function "-" (C1,C2 : T_NOMBRE_COMPLEXE) return T_NOMBRE_COMPLEXE; ................ end P_COMPLEXE; Ceci reprsente en quelque sorte un contrat d'utilisation (voir introduction). Ici la structure du type T_NOMBRE_COMPLEXE n'est pas cache l'utilisateur ( revoir). On rappelle quil est possible en Ada de dclarer des fonctions qui renvoient des variables de type composites (ici T_NOMBRE_COMPLEXE). Description dun paquetage. Un paquetage contient un certain nombre de dclarations qui sont utiles ses utilisateurs. Elles sont contenues dans la partie spcifications . On dit que le paquetage les exporte . Cette partie peut tre compile sparment de la partie suivante nomme la partie ralisation (corps ou body) du paquetage. Cette deuxime partie (le corps) contient le code des sous-programmes cest dire la faon de raliser concrtement le problme : en fait, cest ce qui est cach l'utilisateur. Cette deuxime partie s'appelle le corps du paquetage ou package body. Dans notre exemple la partie ralisation (ou corps) ressemblerait ceci : package body P_COMPLEXE is function "+" (C1,C2 : T_NOMBRE_COMPLEXE) return T_NOMBRE_COMPLEXE is begin return (C1.PARTIE_REELLE + C2.PARTIE_REELLE, C1.PARTIE_IMAGINAIRE + C2.PARTIE_IMAGINAIRE); end "+"; function "-" (C1,C2 : T_NOMBRE_COMPLEXE) return T_NOMBRE_COMPLEXE is begin return (C1.PARTIE_REELLE - C2.PARTIE_REELLE, C1.PARTIE_IMAGINAIRE - C2.PARTIE_IMAGINAIRE); end "-"; ......................... end P_COMPLEXE;

Le paquetage envisag P_COMPLEXE existe dj en Ada sous forme de deux paquetages que nous reverrons : Generic_Complex_Types et Generic_Complex_Elementary_Functions. Tout deux issus du paquetage Ada.Numerics. Pour le moment faisons comme sils nexistaient pas ! D. Feneuille I.U.T. Aix 2001 (cours n 7 fichier COURS7.DOC) 03/04/01

3
On peut bien sr augmenter les services rendus par ce paquetage avec par exemple les traditionnelles oprations produit et quotient (il suffit dappliquer les formules dans tous les livres de math de terminale !). On peut aussi ajouter les oprations lmentaires dentres - sorties (LIRE et ECRIRE). A faire ! ? En rsum : Partie dclaration (spcifications) : La forme gnrale d'une spcification de paquetage est la suivante : {clause with} -- importation ventuelle d'un ou d'autres paquetages ncessaires aux dclarations package NOM_DU_PAQUETAGE is { dclaration des types, constantes, variables, exceptions, sous-programmes, sous-paquetages, tches, etc. exporter } { private partie prive } end NOM_DU_PAQUETAGE; Remarque : la partie prive contient, entre autre, la description des types privs et limits privs exports par le paquetage et dclars avec is private dans les s pcifications. Cette partie sera explicite plus loin. Partie corps ou ralisation (implmentation) :

La partie corps a la forme suivante (notez bien le mot body en plus) : {clause with} -- importation ventuelle d'un ou d'autres paquetages ncessaires l'implmentation package body NOM_DU_PAQUETAGE is dclarations locales au corps du paquetage ralisation complte des types ralisation complte des S/P et sous-paquetages de la partie spcifications { begin initialisation du corps (partie optionnelle) } end NOM_DU_PAQUETAGE; Remarques : Notez bien les deux clauses with respectives aux deux parties et qui nont rien voir entre elles. Elles sont optionnelles. La premire sappuie sur des paquetages pour rsoudre les problmes lis aux dclarations tandis que la deuxime clause sappuie sur des paquetages pour rsoudre les implmentations. Le corps d'un paquetage "voit" (cest--dire accde ) toutes les dclarations de la partie spcifications (y compris les with ventuels quil ne faut pas dclarer nouveau). Le corps du paquetage est obligatoire si la dclaration du paquetage exporte des objets qui ont eux-mmes un corps (S/P, tches, sous paquetages). Si les spcifications n'exportent que des types, des constantes ou des renommages de sous-programmes le " body" ne s'impose videmment pas. Les objets dclars dans un corps de paquetage ne sont pas accessibles par les autres units . Le principe : sparation des spcifications, de la ralisation existe dj pour les sous programme (cours n5) mais il est optionnel ! Les spcifications et le corps d'un paquetage peuvent tre compils sparment.

Avec cette dernire remarque le corps du paquetage peut tre ralis : longtemps aprs (sans retarder lavancement du projet), par une autre quipe (qui respectera les spcifications), de diffrentes manires sans gner l'utilisateur (car le contrat reste invariant).

D. Feneuille I.U.T. Aix 2001 (cours n 7 fichier COURS7.DOC) 03/04/01

4
Utilisation d'un paquetage. Quelques rappels : Pour rendre visible (donc utilisable) un paquetage par une unit de compilation utilisatrice (programme excutable ou autre paquetage), on fait prcder la dclaration de lunit utilisatrice d'une clause with qui voque le paquetage utiliser. Tout objet utilis l'extrieur d'un paquetage qui le dfinit doit tre prfix par le nom du paquetage. L'usage de la clause use simplifie les critures (en nobligeant pas le prfixage) mais, dans certains cas, gnre des ambiguts possibles ( revoir).

Exemple dutilisation de notre paquetage : with P_COMPLEXE; procedure TEST_COMPLEXE is use COMPLEXE; Z, X : T_NOMBRE_COMPLEXE; I : T_NOMBRE_COMPLEXE := (0.0,1.0); -- initialisation par agrgat begin X := (1.0, 0.5); Z := X + I; -- il faudrait diter le rsultat! end TEST_COMPLEXE; L'utilisation d'un bloc pour limiter la porte d'un use est recommande (nous en reparlerons).

Paquetage et types privs.


Les types en Ada sont diviss en deux catgories : d'une part les types dont la structure est connue des utilisateurs (types numratifs, types tableaux etc. sans oublier peut-tre les types prdfinis !). d'autre part les types dits privs (ou fonctionnels) dont la structure doit rester cache (i.e. inaccessible).

Dclaration de type priv. La dclaration d'un type priv doit ncessairement se trouver dans la partie spcifications d'un paquetage. La syntaxe de cette dclaration est : type T_NOM_DU_TYPE is private;

Comme nous l'avons vu prcdemment, il est possible, dans la partie dclaration, de dclarer : des constantes, des sous-programmes, etc. Do les constantes dun type priv dj dclar : C_DU_TYPE : constant T_NOM_DU_TYPE;

et les sous-programmes portant sur les types privs : function MA_FONC (LISTE_DE_PARAMETRES) return T_NOM_DU_TYPE;

Exemple (reprenons nos complexes) : La visibilit de la structure permettant dimplmenter nos complexes (avec partie relle et partie imaginaire) nest pas ncessaire pour lutilisateur. Que lui importe de savoir si les complexes sont raliss avec cette proprit plutt quavec celle de module et argument par exemple ! Do :

D. Feneuille I.U.T. Aix 2001 (cours n 7 fichier COURS7.DOC) 03/04/01

5
package P_COMPLEXE is

type

T_NOMBRE_COMPLEXE

is private;

function "+" (C1,C2 : T_NOMBRE_COMPLEXE) return T_NOMBRE_COMPLEXE; function "-" (C1,C2 : T_NOMBRE_COMPLEXE) return T_NOMBRE_COMPLEXE; -- dautres oprateurs faire! procedure LIRE (C : out T_ NOMBRE_COMPLEXE); procedure ECRIRE (C : in T_ NOMBRE_COMPLEXE);

private type T_NOMBRE_COMPLEXE is record PARTIE_REELLE : FLOAT; PARTIE_IMAGINAIRE : FLOAT; end record; end P_COMPLEXE;

Partie visible donc utilisable.


Partie cache i.e. inaccessible pour lutilisateur

Remarques (voir aussi le synoptique page 9 plus loin) : La privatisation de la structure ralisant le nombre complexe cache certes la visibilit (mais pas la lisibilit !) de lobjet mais en consquence (et surtout) empche lutilisateur daccder la structure. Aussi doit-on absolument fournir des outils pour (par exemple) construire (LIRE) et voir (ECRIRE) ces objets. Plus tard on verra aussi les notions daccesseurs et de modifieurs. Pour que le compilateur puisse raliser les variables du type priv il faudra bien, un moment donn, dcrire effectivement la structure de ce type priv. Cette structure sera dcrite dans la partie prive du paquetage. Elle est lisible mais ... pas "visible" cest--dire inaccessible lutilisateur du paquetage ! La ralisation de notre nouveau paquetage P_COMPLEXE (cest--dire le corps) restera la mme que lors de la premire ralisation (voir le corps pages prcdentes) car la structure cache lutilisateur (invariante !) est accessible, elle, au concepteur (ou ralisateur) du paquetage. Utilisation du type priv et des mthodes associes. A l'extrieur du paquetage et grce la clause with le type devient utilisable et il sera possible de dclarer des variables et utiliser les sous-programmes rfrenant le type priv. On voit donc que le paquetage exporte donc non seulement une structure dobjet mais aussi un ensemble dentits qui lui sont connexes (sousprogrammes par exemple). Ceci est la base de ce que lon nomme le type abstrait de donnes (T.A.D.) nous y reviendrons (cours n10). Oprations sur les types privs. Les seules oprations prdfinies sur les types privs sont l'affectation et la comparaison. Un type priv n'autorisera donc que les oprations suivantes (rappel) : affectation d'une variable de ce type : VAR := expression_du_type; test d'galit : VAR1 = VAR2; test d'ingalit : VAR1 /= VAR2;

Exemples : On verra avec intrt les T.A.D. suivants : rationnels cest lobjet du TD-TP Ada n11 ! T_Chaine dans le fichier chaine.doc (CDRom) lire !

D. Feneuille I.U.T. Aix 2001 (cours n 7 fichier COURS7.DOC) 03/04/01

6
Un autre exemple de type de donnes abstraites : le type ensemble de ...... (type discret) package P_ENSEMBLE_DE_....... is type T_ENSEMBLE is private; ENSEMBLE_VIDE : constant T_ENSEMBLE; function "&" (E : in T_ENSEMBLE; ELEM : in T_DISCRET) return T_ENSEMBLE; -- ajoute un lment lensemble; function "+"(E,F : in T_ENSEMBLE ) return T_ENSEMBLE; -- union function "*"(E,F : in T_ENSEMBLE ) return T_ENSEMBLE; -- intersection function APPARTIENT (ELEM : in T_DISCRET; E : in T_ENSEMBLE) return BOOLEAN; -- la surcharge avec in nest pas possible private type T_ENSEMBLE is array (T_DISCRET) of BOOLEAN; ENSEMBLE_VIDE : constant T_ENSEMBLE := (others => FALSE); P_ENSEMBLE_DE_......;
3

end

La prsentation est gnrale (la ralisation peut dailleurs tre gnrique : concept revoir). Le type T_DISCRET est soit un type prdfini discret (CHARACTER par exemple), soit numratif, soit un sous type dun type prdfini (par exemple un sous type de INTEGER). La ralisation peut simplement tre ralise ainsi : package body P_ENSEMBLE_DE_....... is function "&" (E : in T_ENSEMBLE; ELEM : in T_DISCRET) return T_ENSEMBLE is begin return E(T_DISCRETFIRST..T_DISCRETPRED(ELEM)) & TRUE & E(T_DISCRETSUCC(ELEM)..T_DISCRETLAST); exception --...... revoir end "&"; function "+"(E,F : in T_ENSEMBLE ) return T_ENSEMBLE is begin return E or F; end "+"; function "*"(E,F : in T_ENSEMBLE ) return T_ENSEMBLE is begin return E and F; end "*"; function APPARTIENT (ELEM : in T_DISCRET; E : in T_ENSEMBLE) return BOOLEAN is begin return E(ELEM); end APPARTIENT; end P_ENSEMBLE_DE_........; L'utilisation ( finir et mettre en uvre) a lallure suivante: with P_ENSEMBLE_DE_..........; procedure TEST_ENSEMBLE is use P_ENSEMBLE_DE_.......; begin .......... imaginer! .......... end TEST_ENSEMBLE;

Fort classique qui trane dans tous les bons ouvrages ! A connatre ! D. Feneuille I.U.T. Aix 2001 (cours n 7 fichier COURS7.DOC) 03/04/01

7 Les types privs limits.


Les types privs limits sont des types privs dont l'utilisation est encore plus restreinte . Ils ne possdent plus ni la comparaison ni l'affectation. La seule chose que l'on puisse faire avec un type priv limit, c'est de dclarer des variables et utiliser les sous-programmes fournis par le paquetage (sans affectation ni comparaison). Ces techniques permettent un contrle total sur leur utilisation. Un type priv limit se dclare de la faon suivante : type T_EXEMPLE is limited private ; Un exemple classique de type priv limit est le type fichier. Il est possible de dclarer des variables de type fichier, il est possible de raliser certaines oprations (ouverture, fermeture, lecture etc.), mais la comparaison ou l'affectation de deux fichiers sont interdites (cela aurait-il d'ailleurs un sens ?). A revoir avec ltude approfondie de ADA.TEXT_IO, ADA.SEQUENTIAL_IO, ADA.DIRECT_IO et ADA.STREAM_IO dans les TD-TP fichiers venir. On verra aussi en TD TP n10 lexemple trs classique de la ralisation dune pile (type abstrait de donnes limit priv par excellence). Remarque : Une bonne pratique de programmation consiste n'exporter qu'un unique type priv par paquetage avec les oprations applicables sur ce type. (C'est la notion de type abstrait de donnes et on se rapproche alors du concept d'objet plus gnral encore).

Diffrents emplacements d'un paquetage :


Paquetage en tant qu'unit de compilation (le plus utilis). package NOM_DE_PAQUETAGE is -- les spcifications end NOM_DE_PAQUETAGE; Puis dans la foule ou ailleurs (cest mieux!), mais sparment, le corps du paquetage. package body NOM_DE_PAQUETAGE is -- implmentation des spcifications end NOM_DE_PAQUETAGE; Un paquetage peut tre dclar dans un bloc. NOM_DU_BLOC : declare package P_TRUC is .........-- spcifications end P_TRUC; package body P_TRUC is .........-- corps end P_TRUC; begin -- dbut de porte de P_TRUC ........... P_TRUC.OUTIL (X); -- on utilise P_TRUC ........... end NOM_DU_BLOC; -- fin de porte de P_TRUC Un paquetage peut tre dclar dans une spcification de S/P. procedure NOM_DE_PROCEDURE is package NOM_DE_PAQUETAGE is -interface (partie visible par l'utilisateur) end NOM_DE_PAQUETAGE; package body NOM_DE_PAQUETAGE is -implementation (partie cache) end NOM_DE_PAQUETAGE; begin -corps de procdure -- utilisation des fonctions et procdures du paquetage end NOM_DE_PROCEDURE;

D. Feneuille I.U.T. Aix 2001 (cours n 7 fichier COURS7.DOC) 03/04/01

8
Un paquetage peut tre dclar dans une spcification ou un corps dun autre paquetage. package NOM_DE_PAQUETAGE is package P_EXPORT is -spcifications end P_EXPORT; end NOM_DE_PAQUETAGE; Ce cas est assez utilis voir notamment le paquetage Ada.Text_Io et ses 6 sous paquetages. Ou encore : package body NOM_DE_PAQUETAGE is -dclarations locales package end LOCAL is - - spcifications LOCAL;

end

package body LOCAL is -- implmentation locales end LOCAL; NOM_DE_PAQUETAGE;

La drivation (notion trs forte reprise au cours n10).


De faon gnrale : si T_PERE est un type quelconque, alors, avec la dclaration : type T_NOUVEAU is new T_PERE; On a driv le type T_PERE et T_NOUVEAU est un nouveau type dit driv de T_PERE ; T_PERE est dit le type pre de T_NOUVEAU (notez bien le new). Un type driv appartient la mme classe de types que son pre (si T_PERE est un type article alors T_NOUVEAU sera un type article). L'ensemble des valeurs d'un type driv est une copie de l'ensemble des valeurs du type pre (sauf s'il y a un range, en plus, qui limitera l'intervalle des valeurs hrites). Mais on a quand mme des types diffrents et les valeurs d'un type ne peuvent pas tre affectes des objets de l'autre type. Cependant la conversion entre les deux types est possible. Soit : LE_NEW LE_VIEUX : T_NOUVEAU; : T_PERE;

alors : LE_NEW := LE_VIEUX; -- interdit mais : LE_NEW := T_NOUVEAU(LE_VIEUX); -- possible (conversion) Rgles d'hritage concernant les types drivs. Les oprations applicables aux types drivs sont les suivantes : Un type driv possde les mmes attributs (s'ils existent) que le type pre. L'affectation, l'galit et l'ingalit sont galement applicables sauf si le type pre est limit. Un type driv hritera des sous-programmes (S/P) applicables au type pre. Le type pre est un type prdfini : les S/P hrits se rduisent aux S/P prdfinis, et si le type pre est lui mme un type driv alors les S/P hrits seront de nouveau transmis. Le type pre est d clar dans la partie visible d'un paquetage : tout S/P dclar dans cette partie visible sera hrit par un type driv (le fils) ds quil est dclar. D. Feneuille I.U.T. Aix 2001 (cours n 7 fichier COURS7.DOC) 03/04/01

9
Visibilit des entits : Une flche indique la visibilit cest--dire laccs dune entit sur (vers) une autre. with P2 ; package P1 is

package P2 is

private

end P1 ; private package body P1 is end P2 ;

package body P2 is

end P1 ;

with P1 ; end P2 ; Unit utilisatrice Remarques : Le paquetage P1 ( droite) sappuie sur le paquetage P2 ( gauche) grce au with P2 en haut droite, la partie spcifications de P1 (et aussi la partie prive) voient les spcifications de P2. Lunit utilisatrice (en bas droite) qui sappuie sur P1 ne voit que la partie visible de P1 (elle se voit rien de P2, elle ne peut y accder). Il ny a pas transitivit des with. Le corps de P1 voit aussi la partie spcifications de P2 grce au with P2 dclar avec les spcifications de P1. (mais le corps de P1 ne voit pas la partie prive de P2) Les corps des paquetages (body) ont accs leurs spcifications respectives ainsi qu leur partie prive. Les parties prives ont accs leurs spcifications. Aucune entit na accs aux corps des paquetages.

D. Feneuille I.U.T. Aix 2001 (cours n 7 fichier COURS7.DOC) 03/04/01

10 Le surnommage (renames).
Cette dclaration sapplique gnralement aux sous programmes. Elle permet, dans la partie spcifications dun paquetage notamment, de ne pas dfinir, dans le corps du paquetage correspondant, la ralisation du sous programme dclar. Voir par exemple dans P_E_SORTIE (cours n1 gnralits III) : procedure ECRIRE (CARAC : CHARACTER) renames ADA.TEXT_IO.PUT ; La procdure ECRIRE est dclare comme tant la mme que la procdure PUT du paquetage ADA.TEXT_IO. Ceci nous dispense davoir raliser, dans le body de P_E_SORTIE, le corps de la procdure ECRIRE. Cette dclaration renames est utile si lon souhaite faire remonter une unit utilisatrice dun paquetage des ressources inaccessibles par transitivit dun autre paquetage. Voir la page prcdente o lunit utilisatrice sappuie sur P1 qui sappuie lui mme sur P2 et lunit utilisatrice na pas accs P2 ! La partie spcifications de P1 peut offrir ses utilisateurs quelques ressources de P2 en les surnommant dans ses spcifications : with P2 ; package P1 is . procedure COUPER (paramtres formels) renames P2.COUPER ; . end P1 ; On voit que lutilisateur de P1 a accs COUPER de P1 qui nest rien dautre que le COUPER de P2. On remarque aussi que lon nest pas oblig de changer de nom comme nous lavions fait avec ECRIRE et PUT. On peut surnommer aussi : des units de bibliothque, des variables (commodes avec les champs des articles et les tranches de tableaux), des constantes et des exceptions (cours n8). On ne peut surnommer un type ! Si lon souhaite faire remonter un type, on utilise, toujours dans la partie spcifications, la technique de dfinition dun sous type identique un type tel que : subtype T_JOUR is P2.T_JOUR ;

Conception oriente objet. ( lire pour le moment et approfondir au cours n10!)


Les objets manipuls par un programme peuvent tre trs divers (nombres, tables, dictionnaires, texte, etc...). Ils peuvent tre aussi trs complexes. Nous avons vu : qu'un objet possde une valeur et une seule un moment donn, que l'excution d'une action tend modifier un ou des objets (variables), que des fonctions et des oprateurs permettent de produire des valeurs partir d'autres valeurs, que c'est le type de l'objet qui dtermine l'ensemble des valeurs que peut prendre un objet, les actions applicables sur l'objet, ainsi que les fonctions oprant sur les valeurs. En Ada les paquetages sont le support de la notion de "conception oriente objet". En effet les paquetages exportent des types d'objets ainsi que les actions applicables sur ces objets (cest le concept de type abstrait de donnes). Ainsi Ada permet de dfinir des types abstraits de donnes par les notions de paquetage, de type priv et de compilation spare. La notion de type abstrait de donnes permet de dcrire un type en sparant la description du type et sa ralisation. Le type abstrait de donnes constitue la base thorique du concept de classe dans les langages orients objets. Il y manque la drivation avec hritage et lvolution de la structure de donnes de base. Ceci est une autre histoire que nous verrons plus tard avec lobjet cours n10. Exercice : Sur le modle de la ralisation du type abstrait de donnes T_COMPLEXE (qui est finir!) on peut raliser le paquetage P_RATIONNELS en utilisant un type article pour la dclaration comp lte du type rationnel (en priv) ainsi que les classiques oprateurs (+,-,*,/). Sans oublier la sparation entre la spcification du type et sa ralisation. Vo ir le TD TP n11. Voir aussi lexemple (fichier chaine.doc dans le CDRom) du type T_CHAINE dont nous avons tant parl. Ces exemples sont gnriques et seront bien compris aprs le cours n9.

D. Feneuille I.U.T. Aix 2001 (cours n 7 fichier COURS7.DOC) 03/04/01

11 Les bibliothques hirarchiques (fils publics, fils privs).


Cette partie est nouvelle (Ada 95) mais a dj t utilise en algorithmique avec le paquetage P_MOUCHERON qui tait le pre des autres paquetages MOUCHERON1, Ce rappel pour bien fixer les ides ! Position du problme. Avant daborder les objets et les classes (un peu de patience cours n10) nous allons montrer une extension apporte au langage Ada pour le dveloppement des grosses applications. En effet, si la distinction spcifications/corps donne de bons rsultats pour des applications modestes , cette proprit a montr ses limites dans le dveloppement dapplications consquentes et incrmentales. A priori quand on cherche tendre des fonctionnalits (par exemple fournir quelques sous programmes supplmentaires) un type abstrait de donnes (TAD) dj dfini dans un paquetage on peut : ajouter les nouvelles fonctionnalits dans la partie (initiale) des spcifications puis les raliser dans le corps largi. Ce faisant, on oblige toutes les applications courantes ou passes nutilisant pas ces fonctionnalits procder des (re)compilations fastidieuses (la partie spcifications ayant chang). On arrive ainsi des paquetages trop importants grer. Recrer un paquetage clone renommant les fonctionnalits premires et faisant remonter tous les types, exceptions, variables et constantes du premier paquetage. Ceci demande aussi ce que le TAD ne soit pas (ou ne soit plus) priv ce qui est loppos de la saine notion dabstraction. Driver le type premier dans un autre paquetage puis ajouter les fonctionnalits mais alors on a cr deux types diffrents obligeant lutilisateur des deux versions des conversions insupportables.

Mais tout ceci est extrmement archa q u e ! Exemple : On veut ajouter des fonctionnalits au type T_COMPLEXE pour certaines applications spcifiques plus gourmandes tout en gardant lintgralit et lintgrit des anciennes spcifications qui donnent satisfaction dans la plupart des applications anciennes, et qui, elles, ne souhaitent pas utiliser les nouvelles fonctionnalits. Solution. Il serait souhaitable de pouvoir tendre un TAD (reprsent par un paquetage) dans ses fonctionnalits grce un paquetage hrit (ou fils) nobligeant aucune recompilation du paquetage pre tout en permettant laccs la structure prive. Cette extension va tre illustre sur notre exemple de T_COMPLEXE. Nous avons dj notre paquetage pre concrtisant le TAD (cf. page 5) : package P_COMPLEXE is type T_COMPLEXE is private; function function function function procedure procedure "+" (C1,C2 : T_NOMBRE_COMPLEXE) return "-" (C1,C2 : T_NOMBRE_COMPLEXE) return "*" (C1,C2 : T_NOMBRE_COMPLEXE) return "/" (C1,C2 : T_NOMBRE_COMPLEXE) return LIRE (C : out T_ NOMBRE_COMPLEXE); ECRIRE (C : in T_ NOMBRE_COMPLEXE); T_NOMBRE_COMPLEXE; T_NOMBRE_COMPLEXE; T_NOMBRE_COMPLEXE; T_NOMBRE_COMPLEXE;

private ........ dfinition du type voir page 5 end P_COMPLEXE; Nous allons augmenter les fonctionnalits de ce paquetage en crant un fils ainsi :

D. Feneuille I.U.T. Aix 2001 (cours n 7 fichier COURS7.DOC) 03/04/01

12
package P_COMPLEXE.ELARGI is function Conjugue (X : T_Complexe) return T_Complexe; function Argument (X : T_Complexe) return Float; function Module (X : T_Complexe) return Float; .......etc. end P_COMPLEXE.ELARGI; On ralise ensuite le corps de ce paquetage comme dhabitude avec compilation spare. package body P_COMPLEXE.ELARGI is Notez le point

function Conjugue (X : T_Complexe) return T_Complex is begin ........ end Conjugue; function Argument (X : T_Complexe) return Float is begin ....... end Argument; ....... end P_COMPLEXE.ELARGI; Le paquetage P_COMPLEXE.ELARGI dnote le paquetage fils du paquetage P_COMPLEXE (cette notion est syntaxiquement illustre par le prfixage en notation : pre.fils ). Il est vident (mais prudent de le signaler) que le corps du paquetage fils a la visibilit sur la partie prive du paquetage pre ! Sinon comment pourrait-il raliser les fonctionnalits supplmentaires sil ne peut accder la structure prive ? A noter aussi que si le fils possde une partie prive alors cette partie prive a aussi visibilit sur la partie prive du pre. Bien sr, la partie visible du fils ne peut avoir accs la partie prive du pre. Voir le nouveau synoptique ci-aprs. Cette technique (pre-fils) sutilise surtout, non pas pour tendre, a posteriori, des fonctionnalits, mais pour construire, a priori, des modules hirarchiques offrant des fonctionnalits allant des plus simples aux plus compliques car la descendance peut tre infinie ! Utilisation par un client dune ressource (o with et use se diffrencient !) : avec la clause with videmment (et ventuellement avec la clause use en plus). Ainsi : with P_COMPLEXE.ELARGI; permet, une procdure client par exemple, et en une seule dclaration, dutiliser les deux ressources, savoir : le pre P_COMPLEXE et aussi le fils P_COMPLEXE.ELARGI. Cependant il faut prfixer : P_COMPLEXE. + ou P_COMPLEXE.ELARGI.Argument respectivement soit avec lidentificateur du pre soit avec celui du fils. La clause use permet soit de ne pas prfixer le pre en crivant use P_COMPLEXE; soit de ne pas prfixer le fils avec use P_COMPLEXE.ELARGI; En aucun cas on ne peut crire use ELARGI mme aprs avoir crit use P_COMPLEXE. Peut-on ne recourir qu un paquetage fils sans recourir son pre ? (puisque with P_COMPLEXE.ELARGI valeur de : with P_COMPLEXE, P_COMPLEXE.ELARGI;). Oui, cest possible, grce la possibilit quoffre Ada de compiler un surnom. Soit les deux lignes : with P_COMPLEXE.ELARGI; package P_COMPLEXE_ETENDU renames P_COMPLEXE.ELARGI; .......... et avec : with P_COMPLEXE_ETENDU; lutilisateur ne peut quaccder P_COMPLEXE_ETENDU donc seulement au fils de P_COMPLEXE. D. Feneuille I.U.T. Aix 2001 (cours n 7 fichier COURS7.DOC) 03/04/01

13

Visibilit des entits (Pre fils). A rapprocher des relations (page 9) entre deux paquetages lis seulement par la relation with.

package Pre.fils is

package Pre is

private

end Pre.fils ; private package body Pre.fils is end Pre;

package body Pre is

end Pre.fils ;

with Pre.fils ; end Pre ; Unit utilisatrice Remarques : Notez labsence de with pour le paquetage fils droite. Le fait de citer son pre en prfixe (Pre.fils) suffit. Lunit utilisatrice en bas droite avec son with Pre.fils sappuie la fois sur le pre et sur le fils (les deux spcifications sont visibles ). La partie prive du fils a accs toutes les spcifications du pre (partie prive du pre incluse). Le corps du fils a accs toutes les spcifications du pre (partie prive incluse). Les parties prives (ainsi que les corps) ont toujours accs leurs spcifications ! Aucune entit na accs aux corps des paquetages. Ce principe na pas chang !

D. Feneuille I.U.T. Aix 2001 (cours n 7 fichier COURS7.DOC) 03/04/01

14
Un paquetage pre peut naturellement avoir plusieurs fils (ils sont alors frres !). On possde l une solution pour le partage dun type priv entre plusieurs units de compilation. En combinant cette approche dextension de fonctionnalits avec celle dextension de structure (voir cours n10 : les types tiquets) on possde un moyen de fournir des vues diffrentes dun type o certains composants seront visibles un utilisateur tandis que dautres lui seront caches. A voir prochainement. Remarques : Un fils peut avoir aussi une partie prive (on la dit) qui ne sera visible que de ses propres descendants (fils, petits-fils) mais ni de son pre ni de ses frres. Un corps de fils dpend de ses ascendants (pre, grand-pre etc.) donc na pas besoin de clause with. Un corps de pre peut avoir accs (avec with) son fils ! (partie spcifications seulement) voir, comme exemple, les sources du reformateur de gnatform. De mme un corps de fils peut aussi (avec with) avoir accs aux spcifications de son frre ! Notez bien : seulement le corps ! Le concept de hirarchie (pre-fils) ne sapplique pas qu lunit de compilation quest le paquetage mais aussi aux procdures. Par exemple : function P_COMPLEXE.Sqrt (X : T_Complexe) return T_Complexe; permet daccder, seulement pour cette fonctionnalit bien prcise, la structure cache des T_Complexe. Un exemple concret (la structure de Ada95). En Ada 95 le paquetage STANDARD est le pre de toutes les units de compilation. Il a trois fils distincts pour regrouper les lments prdfinis ce sont : INTERFACES (qui concerne la liaison avec les autres langages), SYSTEM (pour tout ce qui concerne la dpendance de limplmentation) et ADA (lui-mme pre de trs nombreux paquetages comme TEXT_IO, STRINGS, CHARACTERS, CALENDAR, FINALIZATION, STREAMS, EXCEPTIONS, TAGS, NUMERICS, DECIMAL, COMMAND_LINE, SEQUENTIAL_IO, DIRECT_IO, etc.). On retrouve de vieilles connaissances dj utilis en TD-TP mais beaucoup de petits nouveaux. Voir page suivante quelques dtails et dveloppements intressants. On remarque quil faut nommer ADA.TEXT_IO le paquetage bien connu sur les E/S textes. Mais la dclaration suivante peut nous en dispenser (parfois prdfinie dans certains compilateurs) : with ADA.TEXT_IO; package TEXT_IO renames ADA.TEXT_IO; Cette technique a dj t voque prcdemment page 12 (compilation dun surnom). Les fils privs (restriction des fils publics). Le qualificatif de fils priv est obtenu en ajoutant, avant la dclaration, le mot rserv private ainsi : private package P_COMPLEXE.LE_PRIVE is ...... end P_COMPLEXE.LE_PRIVE; Ce fils dit priv P_COMPLEXE.LE_PRIVE a donc un pre : P_COMPLEXE videmment et au moins un frre (non priv) : P_COMPLEXE.ELARGI. Les proprits de ce fils priv est de ntre visible que de lintrieur du sous arbre de la hirarchie familiale. Il nest donc pas connu dun client traditionnel de la famille P_COMPLEXE. De plus il nest plus visible aux spcifications des frres (ceux qui sont non privs seulement). Il reste cependant visible aux corps de tous les membres de la famille. Grce ces proprits la partie visible du fils priv peut maintenant avoir accs la partie prive du pre car il ne risque plus dexporter les informations prives du pre vers les utilisateurs! Les fils gnriques. Cette partie sera dveloppe cours n9 avec ltude des gnriques. D. Feneuille I.U.T. Aix 2001 (cours n 7 fichier COURS7.DOC) 03/04/01

15
Panorama de lorganisation des paquetages et des sous paquetages Ada95 : Paquetages utilisateurs

S tandard (voir son dtail dans le polycopi paquetages )

Ada IO_Exceptions Sequential_IO Pointers Direct_IO COBOL Text_io FORTRAN Editing Complex_IO System Text_Streams Machine_Code Wide_Text_IO Storage_Elements Editing Storage_Pools Complex_IO Address_To_Access_Conversion RPC Text_Streams Storage_IO Streams Streams_IO Remarques : Finalization Le paquetage Standard (rappel) dfinit les types prdfinis, il fait rfrence aux types racines (root_real et root_integer). Il est Exceptions Tags toujours le seul ne pas tre prfixable. Le(s) paquetage(s) utilisateur(s) sappuie(nt) automatiquement sur le Calendar Command_Line paquetage Standard donc sont fils implicite(s) de celui-ci. Characters Le paquetage System est trs spcialis . A voir pour les fanatiques ! Latin_1 On trouve souvent sur Internet des paquetages utilisateurs libres (free) qui Handling permettent de rgler les problmes courants. Une bonne recherche vite Strings souvent de rinventer la roue ! ......... 4 Numerics Les paquetages intressants (voyez aussi Smith ) : ....... Decimal Ada.Command_Line (Smith page 435 en bas) ....... Ada.IO_Exceptions (Smith page 422) et encore dautres ..... Ada.Text_IO (Smith page 422) Ada.Strings.Bounded (Smith page 429) Ada.Numerics (Smith page 434) Ada.Numerics.Generic_elementary_functions (Smith page 435 haut) Ada.Calendar (Smith page 436) Ada.Characters.Handling (Smith page 428) Ada.Finalization (Smith page 436) Ada.Tags (Smith page 436) Interfaces.C (Smith page 433) Ada.Sequential_IO (Smith page 427) System (Smith page 437) On rappelle que tous ces paquetages doivent tre consultables rapidement pour tre utiliss avec efficacit. Donc il faut absolument en avoir une copie lisible avec soi (la plupart sont sur le polycopi paquetages !).

Interfaces Langage C Strings

Object-Oriented Software in Ada 95 (livr avec les 5 compilateurs Aonix) en bibliothque. D. Feneuille I.U.T. Aix 2001 (cours n 7 fichier COURS7.DOC) 03/04/01

Cours 8 Ada les exceptions (2 heures) Thme : les exceptions


Avertissement : Comme pour les paquetages nous avons dj t amens, au cours des TP de programmation, parler des exceptions et les utiliser de faon trs implicite. Cest le moment (semaine 6 !) de structurer tout cela ! Une remarquable analyse des exceptions est faite par J.P. Rosen dans son livre (ouvrage recommand dans le cours n1). Voir le chapitre 20.4 Politiques de gestion des erreurs pages 275 285 (tout y est !). Les exceptions existent en Ada depuis son origine 83, de nombreux langages ns aprs lui (C++, Java et mme Eiffel) ont adopt des fonctionnalits identiques. En Ada95 des ajouts intressants sont venus les complter. Introduction. Au cours du droulement d'un programme, des erreurs peuvent perturber son fonctionnement : division par zro, dpassement de bornes d'un tableau, initialisation hors des valeurs du type, fichier inexistant, etc. pour ne citer que les plus classiques. Imaginons un T.A.D. pour lequel on souhaite prendre en compte des anomalies ventuelles de fonctionnement. Une astuce pourrait consister ajouter un paramtre boolen aux procdures pour indiquer en sortie leur russite ou leur chec ! A charge pour lutilisateur den prendre connaissance et dutiliser cette information. Solution lourde ! Ada permet les exceptions : solution originale notre problme. En Ada une exception est associe un vnement exceptionnel ncessitant l'arrt du traitement normal et impliquant un traitement particulier. Notez que lon a prfr parler dvnement exceptionnel (ou de situation anormale) plutt que derreur (trop pjorative) mme si cest souvent le cas. On distingue dune part la leve de lexception (ou son dclenchement), cause justement de lvnement anormal qui sest produit, et dautre part le traitement de lexception (que fait-on quand lvnement anormal mest signal ? Comment ragir ?). De nombreuses leves dexception peuvent tre vites par des tests intelligents de diagnostic (tests logiques). Par exemple utiliser End_Of_File pour viter lexception End_Error lorsque lalgorithme persiste lire au del du fichier ! Dans un autre ordre dides un langage qui ne signalerait pas quune condition anormale sest produite est un langage inachev voire dangereux. Jai souvenir du Turbo Pascal qui, quand un entier tait satur (32767), continuait cumuler avec des valeurs .. ngatives ! Comme le dit Rosen il y a pire quun programme qui se plante cest un programme qui dlivre des rsultats faux mais vraisemblables . Une exception en Ada est dclenche par : le matriel l'excutif Ada ou lenvironnement (par exemple en E/S manipulation incorrecte de fichiers), le programme lui-mme. Dans ce dernier cas (dclenche par le programme lui-mme) alors il sagit : dexceptions prdfinies qui se dclenchent lorsque les erreurs se produisent. dexceptions dfinies dans le programme dont le dclenchement est explicite (voir linstruction raise et plus rcemment (Ada95) et encore mieux Raise_Exception). Ces leves dexceptions sont utilises lorsqu'un test logique sur des variables ou des attributs dtecte une anomalie. Toute exception dclenche lors de l'excution d'une unit de programme est normalement propage l'unit appelante. Cette propagation peut continuer jusqu' provoquer l'arrt du programme. Que faire pour viter l'arrt du programme (propagation en cascade). Il suffit de traiter lexception cest--dire mettre en uvre une squence dinstructions particulires qui se substitue la suite dinstructions normales qui ne doivent plus seffectuer. En Ada une exception peut tre traite localement (cest--dire dans l'unit de programme o l'excution l'a dclenche) ou alors propage (donc leve nouveau) l'unit appelante pour subir peut-tre cet endroit un traitement appropri. Dans le cas contraire (non prise en compte de lexception) la propagation continue jusqu peut-tre arriver au programme principal qui avorte lamentablement. Mais comme on la dit mieux vaut peut-tre cela quun traitement erron qui continue. Affaire de got !

2 Mais avant dtre leve pour tre ventuellement traite une exception se dclare !

Dclaration dune exception.


Une exception est soit : prdfinie (dans le paquetage Standard). fournie par un paquetage spcifique (IO_EXCEPTION par exemple). dclare par l'utilisateur (avec le mot rserv exception). On examinera les trois cas de dclarations et des exemples. Les exceptions prdfinies (qui ne se dclarent donc pas !)

Elles sont dclares dans le paquetage STANDARD, c'est--dire l'environnement dans lequel se trouve toute application. Essentiellement on a les quatre exceptions suivantes : CONSTRAINT_ERROR Un tableau est index en dehors de ses bornes. Un champ d'article est inexistant. Un accs est nul Erreur dans un calcul (dbordement par exemple) Appel de S/P non encore labor 1 (S/P separate). Sortie de fonction sans passer par return. Logique de communication entre tches mise en cause. (voir cours TACHES) Place mmoire insuffisante (voir exemples avec la rcursivit). cite pour mmoire (obsolte) confondue avec CONSTRAINT_ERROR !

PROGRAM_ERROR TASKING_ERROR STORAGE_ERROR NUMERIC_ERROR

Les exceptions fournies par un paquetage connu (surtout IO_EXCEPTIONS) voir le cours n11 venir (fichiers) et voyez lannexe A.13 dans le polycopi paquetages . .

Voyons les exceptions lies aux E/S dont la dclaration est faite dans le paquetage IO_EXCEPTIONS. STATUS_ERROR NAME_ERROR USE_ERROR END_ERROR DATA_ERROR LAYOUT_ERROR MODE_ERROR DEVICE_ERROR L'tat du fichier utilis est incorrect (travail sur fichier non ouvert par exemple). Le nom physique du fichier est incorrect (ou le fichier est absent). L'utilisation du fichier est incorrecte. (ex: ouverture en accs direct d'un fichier squentiel.) Fin de fichier "dpasse". Donne incorrecte (ce que l'on lit n'est pas du type dclar). Chane trop longue pour impression Mode dutilisation incorrect (criture sur fichier ouvert en lecture). Utilisation incorrecte du matriel (priphriques par exemple).

Les exceptions dclares par l'utilisateur. Une dclaration d'exception peut apparatre dans n'importe quelle partie dclarative d'un bloc ou d'une unit (fonction, procdure, paquetage). Il suffit dutiliser le mot rserv exception ! -- partie dclaration EXC_MOT_TROP_LONG : exception; -- est dclare par le programmeur EXC_VALEUR_NON_TROUVEE : exception ; Notez quil est recommand de prfixer les exceptions utilisateur par EXC_ ceci pour une meilleure lisibilit du programme ; de la mme manire que nous avions recommand de prfixer les types par T_.

Voir ce sujet les pragmas Elaborate, Elaborate_All et Elaborate_Body. D. Feneuille I.U.T. Aix 2001 (Cours n 8 fichier COURS8.DOC) 04/04/01

Le traitement des exceptions dclenches.


Rappel : Un bloc est constitu de deux parties : une partie dclarative et un corps : {declare} -- declare ou en-tte d'un sous-programme {partie dclaration} begin Cest ici (partie exception) partie instructions que lon traite les exceptions leves dans la .............. {exception partie instructions partie exception} end; Remarque : {declare} -- declare ou en-tte d'un sous-programme {partie dclaration} begin Si lexception est leve avant le begin, donc partie instructions llaboration des dclarations, elle ne peut pas tre .............. traite dans la fin de bloc! Voir plus loin ! {exception partie exception} end; Un bloc ou plus gnralement une unit (fonction, procdure) peuvent contenir une squence de traitement des exceptions , commenant au mot exception et se terminant au mot end du bloc ou de l'unit. La partie exception contient un ou plusieurs rcuprateurs d'exceptions qui ont pour rle d'effectuer un traitement lorsque certaines exceptions sont dclenches ou propages dans le bloc ou l'unit. On peut crire plusieurs traitements d'exception entre les dlimiteurs exception et end. Exemple (analogue la syntaxe du case !) : begin ........... exception when CONSTRAINT_ERROR when STORAGE_ERROR when others end;

=> PUT("Erreur numrique "); => PUT("Mmoire insuffisante "); => PUT("Autre erreur. ");

Remarques : On notera que le contrle ne peut jamais tre rendu ensuite au cadre o exception a t leve. La suite d'instructions suivant le symbole => contient le traitement d'exception et achve ainsi l'excution du cadre. Par consquent pour une fonction un traitement d'exception doit comporter aussi une instruction return pour fournir un rsultat (sinon on retourne lexception PROGRAM_ERROR) moins que le traitement d'exception consiste lever nouveau une exception (raise). function DEMAIN (AUJOURD_HUI : T_JOUR) return T_JOUR is begin return T_JOUR'SUCC(AUJOURD_HUI); exception when CONSTRAINT_ERROR => return T_JOUR'FIRST; end DEMAIN; Les instructions de traitement d'exception peuvent tre aussi complexes que l'on veut (les exemples avec PUT plus haut sont caricaturaux !). Les instructions de traitement dexception peuvent comprendre des blocs, des appels de S/P, et mme des leves d'exceptions ou des traitements dexception, etc.

D. Feneuille I.U.T. Aix 2001 (Cours n 8 fichier COURS8.DOC) 04/04/01

Dclenchement (ou leve) et ventuellement propagation dune exception.


Lever une exception. On dit galement dclencher l'exception (raise en anglais) par exemple avec linstruction : raise NOM_DE_L_EXCEPTION; -- lexception est leve signifie que l'algorithme s'apercevant d'un problme dclenche l'exception. Lalgorithme ne continue pas en squence. Il est interrompu et dirig vers lventuel traitement prvu en fin de bloc . Exemple : -- partie dclaration EXC_ERREUR_ACQUISITION : exception; EXC_ERREUR_CALCUL : exception; begin ........... if (......) then raise EXC_ERREUR_ACQUISITION; end if; ........... if (.......) then raise EXC_ERREUR_CALCUL; end if; ........... exception when EXC_ERREUR_ACQUISITION when EXC_ERREUR_CALCUL when others end;

Schma classique de validation ou test de cohrence. A approfondir voir plus loin.

=> => =>

TRAITEMENT_1; TRAITEMENT_2; TRAITEMENT_3;

Exemple (connu !) : Lecture valide (d'un entier de type T_ENTIER) sur le modle de la lecture valide dun numratif dj largement utilise! Attention : le bloc est dans un loop. procedure LIRE (RES : out T_ENTIER) is L: T_ENTIER ; begin loop declare -- pour traiter l'exception sur le champ c'est--dire tout de suite et -- non en fin de procdure il faut utiliser un bloc qui possde un end begin GET (L); Notez ces SKIP_LINE ; SKIP_LINE exit; (voir cours E/S) exception when DATA_ERROR => SKIP_LINE; PUT_LINE ("Un entier S.V.P "); end; -- fin de bloc end loop; RES := L; -- fin du traitement avec acquisition correcte end LIRE; On verra dans le cours fichier la traditionnelle procdure OUVRIR dun fichier. Remarque: Quelquefois il est pratique de traiter l'exception puis de propager la mme exception. .. when others => PUT("Autre erreur "); raise; end; voir complment ce sujet page 8. D. Feneuille I.U.T. Aix 2001 (Cours n 8 fichier COURS8.DOC) 04/04/01

5 Propagation d'une exception. Le dclenchement d'une exception entrane l'abandon de l'excution normale de la squence restante du bloc de l'unit o a lieu l'exception (bis !) . Si le bloc comporte un traitement pour cette exception alors il y a excution de l'action associe ce traitement, l'unit en cours se terminant aprs le traitement de l'exception. Ceci correspond l'exemple donn (dans ce cas il n'y a pas de propagation). Le contrle est ensuite rendu lunit appelante . Si le bloc ne comporte pas de rcuprateur pour cette exception alors l'unit (o a lieu l'exception) se termine l'instruction qui l'a dclenche. Cette exception est propage l'unit appelante. Cette propagation continue tant que l'unit qui la reoit n'a pas de rcuprateur pour cette exception. Dans les cas extrmes le programme avorte au programme principal avec lexception PROGRAM_ERROR.

Porte des exceptions, problmes divers. Une exception peut tre rendue visible par la notation pointe. Dans l'exemple de la pile (voir TD associ) sans la clause use PILE il faut crire: when PILE.EXC_PILE_PLEINE => ........... ; when PILE.EXC_PILE_VIDE => ........... ;

Une exception peut tre renomme : EXC_DEBORDEMENT_HAUT : exception renames PILE.EXC_PILE_PLEINE; EXC_DEBORDEMENT_BAS : exception renames PILE.EXC_PILE_VIDE; Lexemple le plus classique de renommage est celui du paquetage ADA.TEXT_IO qui renomme les exceptions de IO_EXCEPTIONS en utilisant les mmes identificateurs (voir annexe A.13. polycopi paquetages ... ) Une exception utilisateur, donc dclare, peut tre propage hors de sa porte. Mais alors elle ne pourra tre traite que par others anonymement car son identificateur est inconnu sauf marquage spcial ( voir).

Exemple : declare procedure PROC is EXC_X : exception; begin raise EXC_X; end PROC; begin -- du bloc PROC; ................... exception when others = > ......... end;

leve de EXC_X

EXC_X non traite, elle est propage ici aprs lappel! EXC_X est traitable ici mais pas sous son nom devenue anonyme !

PROC dclare et lve EXC_X mais ne la traite pas. Donc EXC_X est propage au bloc utilisant PROC o elle peut tre traite (mais pas sous son nom elle est devenue anonyme! Il faut utiliser others). Voir cependant plus loin RAISE_EXCEPTION. Une exception peut tre leve llaboration dune dclaration (danger ! voir page 3). N : POSITIVE := 0; --lvera CONSTRAINT_ERROR.

Ainsi :

Retenir : Une exception leve dans llaboration dune dclaration n'est pas traite par le traitement d'exception du cadre contenant la dclaration, mais est immdiatement propage au niveau suprieur (donc prudence !). Cette proprit peut tre utilise pour faire la chasse aux codes morts voir la dmonstration en cours.

D. Feneuille I.U.T. Aix 2001 (Cours n 8 fichier COURS8.DOC) 04/04/01

6 Cas d'une procdure rcursive contenant une dclaration d'exception. Contrairement aux variables dclares dans une procdure on n'obtient pas de nouvelle exception pour chaque appel rcursif. Chaque appel rcursif se rfrera la mme exception. Exemple : procedure F(N : INTEGER) is Attention exemple EXC_X : exception; pdagogique uniquement ! begin if N = 0 then raise EXC_X; end if; F(N-1); exception when EXC_X => PUT ("Je la tiens "); PUT(N); end F;

Avec F(4) on obtient les appels rcursifs F(3), F(2), F(1), F(0) (cf. TD rcursivit!). Quand F est appele avec un paramtre nul, F lve l'exception qui imprime le message Je la tiens et dite la valeur 0. L'exception ne sera plus traite et sortira du cadre du premier appel. Si nous crivons: exception when EXC_X raise; end;

=> PUT("Je la tiens "); PUT (N); En plus

Dans ce cas F(0) lve tout d'abord l'exception qui est ensuite leve anonymement chaque appel rcursif et le message apparatra alors cinq fois. Utilisation des exceptions dans lcriture dune fonction de validation dun objet quelconque : function EST_VALIDE (OBJET : in T_OBJET) return boolean is ... begin ... if (test_spcifique_de_non_validit_de_lobjet) then return FALSE ; end if ; ... -- on rpte la squence ci-dessus avec dautres tests spcifiques ... ACTION(OBJET) ; -- qui dclenche peut-tre une exception ... -- on rpte la squence ci-dessus avec dautres actions ... return TRUE ; -- tout cest bien pass ! exception when others => return FALSE ; end EST_VALIDE ; voir aussi les remarques de Barnes page 575.

D. Feneuille I.U.T. Aix 2001 (Cours n 8 fichier COURS8.DOC) 04/04/01

Complments privilgier.
La fonction de validation dun objet (voir son schma gnral ci-dessus) peut tre complte par une meilleure connaissance des anomalies dclenches. En effet il est toujours frustrant de traiter des exceptions par : exception when others => ... ; La gestion des exceptions traites (par exemple mise en place dune trace des anomalies dans la phase de mise au point dun logiciel appele debuggage en jargon informatique) nest gure facile car les exceptions (si elles ont bien un identificateur local ) ne peuvent tre repres beaucoup plus loin (hors du bloc de dclaration) dans le droulement du programme. Il peut tre intressant de mieux documenter une exception en la levant et de rcuprer cette documentation le moment opportun i.e. dans le traitement. Le paquetage ADA.EXCEPTIONS (voir dans polycopi paquetages en 11.4.1 ) propose pour une meilleure gestion des exceptions notamment les entits suivantes dtailler : des fonctions : EXCEPTION_NAME, EXCEPTION_MESSAGE et EXCEPTION_INFORMATION. des procdures : RAISE_EXCEPTION, SAVE_OCCURRENCE deux types : EXCEPTION_ID, EXCEPTION_OCCURRENCE Capture et dition de lidentit dune exception. EXCEPTION_ID de type private permet de manipuler lidentit dune exception. Pour fixer les ides on peut comprendre par identit au moins le nom complet de lexception (prfixe compris cest--dire lunit dans laquelle elle est dclare). Lassociation entre une exception et son identit se fait grce lattribut Identity. Par exemple avec les dclarations pralables suivantes : UNE_EXCEP : exception ; -- lidentificateur de lexception IDENT : EXCEPTION_ID ; -- pour capturer son identit Et linstruction : IDENT := UNE_EXCEPIDENTITY ; a captur lidentit de lexception.

La fonction EXCEPTION_NAME utilise avec un paramtre effectif instance de type EXCEPTION_ID retourne un String identifiant compltement lexception associe. Ainsi : PUT_LINE (EXCEPTION_NAME (IDENT)) ; affiche la chane "XXXX.UNE_EXCEP" o XXXX reprsente lidentificateur du sous programme dans lequel lexception UNE_EXCEP est dclare. Comment peut-on associer encore plus de renseignements une exception au moment o elle est dclenche ? Pour ce faire nous disposons de la procdure RAISE_EXCEPTION qui lve, la fois, lexception et qui la documente. Remarquez et notez que cette procdure utilise en paramtre lidentit de lexception et non pas lexception elle mme qui est cependant leve. Exemples : RAISE_EXCEPTION (UNE_EXCEPIdentity, "Erreur de calcul") ; .. RAISE_EXCEPTION (UNE_EXCEPIdentity, "dbordement de tableau") ; Cette technique (plus labore) se substitue alors au schma traditionnel : raise UNE_EXCEP ; raise UNE_EXCEP ;

D. Feneuille I.U.T. Aix 2001 (Cours n 8 fichier COURS8.DOC) 04/04/01

8 La mme exception (UNE_EXCEP), leve deux fois avec RAISE_EXCEPTION, est alors diffrenciable ultrieurement dans un traite exception comme on le verra ci-dessous. Documentation (traage) La documentation de lexception reprsente par une chane de caractres est soit, une documentation dite courte on lappelle MESSAGE, soit une documentation dite longue on lappelle INFORMATION. Voyons maintenant la prise en compte (donc le traitement plus labor) des exceptions leves avec RAISE_EXCEPTION. Comme avec le raise, le traitement se fait dans un rcuprateur dexception (en fin de bloc) mais utilise le type EXCEPTION_OCCURRENCE. Ce type joue le rle dun marqueur pour lexception et il est limit priv . Lassociation entre lexception et son marqueur se fait dans le traite exception. Exemple : MARQUEUR : EXCEPTION_OCCURRENCE ; . . exception when . . when MARQUEUR : others => ; end ; On notera que la variable MARQUEUR na mme pas tre dclare ! Cest ma connaissance, un cas unique en Ada ! MARQUEUR contient : non seulement lidentit de lexception leve et rcupre anonymement avec others mais aussi ventuellement la documentation associe si elle existe (voir RAISE_EXCEPTION ci-dessus). Dans le traite exception (aprs le =>) il est possible de connatre, au choix, respectivement : lidentit, le message ou linformation (identit + message) associs lexception. On utilise pour cela respectivement les fonctions : EXCEPTION_NAME, EXCEPTION_MESSAGE et EXCEPTION_INFORMATION qui retournent un String mais utilisent en paramtre le marqueur dexception et non pas lexception elle-mme. PUT_LINE (EXCEPTION_NAME (MARQUEUR)) ; -- lidentit PUT_LINE (EXCEPTION_MESSAGE (MARQUEUR)) ; -- le message PUT_LINE (EXCEPTION_INFORMATION (MARQUEUR)) ; -- les deux ! Le paquetage ADA.EXCEPTIONS propose encore beaucoup des fonctionnalits et de types dcouvrir. Il est recommand d tudier un listing de ce paquetage. Voir aussi dans Barnes page 308 la possibilit de stocker (avec SAVE_OCCURRENCE) dans un tableau des marqueurs pour un traitement retard. Attention cest coteux ! Remarques : ( propos du raise qui permet de propager la mme exception). Le raise sutilise seul (on la vu) mais seulement dans un traite exception (ce qui est vident). Voici un exemple trs significatif de lintrt de ce raise (cit par J.P. Rosen dans ses fiches pratiques 2).

On trouvera ces fiches pratiques (trs instructives) dans son site http://perso.wanadoo.fr/adalog voyez le lien Articles techniques. Voyez aussi le lien sur le catalogue des principales ressources disponibles via Internet, cest fou ce que lon peut trouver sur Ada. D. Feneuille I.U.T. Aix 2001 (Cours n 8 fichier COURS8.DOC) 04/04/01

9 Problme : Vous souhaitez, dans un traite exception (donc en fin de bloc), faire, pour toutes les exceptions traites, un traitement commun, et ensuite, faire, pour chaque exception, un traitement particulier. Une solution lourde mais correcte pourrait tre : Exception when Constraint_Error => Traitement_Commun ; Traitement_spcial_n1 ; when Data_Error => Traitement_Commun ; Traitement_spcial_n2 ;

when Exc_Valeur_Nulle => Traitement_Commun ; Traitement_spcial_n3 ; when others => Traitement_Commun ; Traitement_spcial_n4 ;

end ... ; Une solution plus lgante : exception when others => Traitement_Commun ; begin raise ; -- notez bien sa place et le deuxime exception when Constraint_Error => Traitement_spcial_n1 when Data_Error => Traitement_spcial_n2 when Exc_Valeur_Nulle => Traitement_spcial_n3 when others => Traitement_spcial_n4 end ; end ... ; Cette dernire solution plus modulaire est bien plus facile maintenir. Celles et ceux que la gestion des erreurs intressent et qui est dailleurs un point capital en informatique scurise trouveront dans le livre de Rosen (voir au dbut de ce chapitre) une tude trs intressante recouvrant : Politique de correction locale Politique de code de retour Politique de droutement Politique du contrat Politique par exceptions simples Politique Omga Politique de gestion centralise

bloc imbriqu ! ; ; ; ;

Trs complet !

D. Feneuille I.U.T. Aix 2001 (Cours n 8 fichier COURS8.DOC) 04/04/01

Cours 9 Ada la gnricit (2 heures) Thme : la gnricit.


Introduction (attention : dure, dure !). La gnricit permet d'largir le contexte d'utilisation d'une unit de programme. Elle permet de dfinir des familles paramtres d'units de programme. Les units d'une mme famille ne diffrant que par un certain nombre de caractristiques dcrites l'aide de paramtres formels gnriques . La cration d'une unit de programme (vraie ou concrte) partir d'une unit gnrique (abstraite ou formelle) est faite par instanciation. On associe les paramtres effectifs aux paramtres formels gnriques (comme pour les associations paramtre effectif paramtre formel des sous programmes). Exemple simple (en cours nous prendrons dautres exemples pour mieux concrtiser ce concept) : Soit la procdure ci-dessous changeant deux objets de type entier : procedure ECHANGE_ENTIER (PREMIER, SECOND : in out T_ENTIER) is TAMPON : T_ENTIER; begin TAMPON := PREMIER; PREMIER := SECOND; SECOND := TAMPON; end ECHANGE_ENTIER; Pour changer deux rels il faut rcrire une nouvelle procdure avec un type FLOAT par exemple remplaant le type T_ENTIER (vive le copier-coller pour les b ufs !). La gnricit va permettre d'crire un moule (un modle) partir duquel on peut crer des procdures spcifiques chaque type, seul le type en question diffre. Le type en question constitue ce que lon appelle un type gnrique. Les paramtres gnriques sont dclars, dabord, la suite du mot cl generic. La dclaration s'arrte la rencontre d'un des 3 mots rservs : procedure, function ou package. Ici, un seul paramtre gnrique ! generic type T_ELEMENT is private; procedure ECHANGE_TOUT (PREMIER, SECOND : in out T_ELEMENT); ... procedure ECHANGE_TOUT (PREMIER, SECOND : in out T_ELEMENT) is TAMPON : T_ELEMENT; begin Notez les deux parties distinctes : TAMPON := PREMIER; spcifications puis ralisation PREMIER := SECOND; SECOND := TAMPON; end ECHANGE_TOUT; Grce la procdure gnrique ECHANGE_TOUT il est possible de crer en les spcialisant par un type prcis , de nouvelles procdures. L'opration de cration est ici l'instanciation de procdures (notez le new). procedure ECHANGE_CARAC is new ECHANGE_TOUT (T_ELEMENT => CHARACTER); procedure ECHANGE_ENTIER is new ECHANGE_TOUT (T_ELEMENT => T_ENTIER); procedure ECHANGE_REEL is new ECHANGE_TOUT (T_ELEMENT => FLOAT); Lassociation par nom est facultative mais est trs lisible et fortement conseille (revoir lagrgation) ! Mise en uvre de la gnricit. La gnricit s'applique deux units de programmes : les sous-programmes (procdure ou fonction). Moins usit. les paquetages. Surtout eux !

2 Une unit gnrique comporte (comme toute unit de programme) une partie spcifications et une partie ralisation (avec corps) qui peuvent tre compils sparment. L'utilisation dune instanciation par exemple d'un paquetage gnrique est possible ds l'opration d'instanciation. Les units gnriques et les instanciations de gnrique peuvent tre des units de bibliothque. Si le paquetage gnrique P_PILE (voir TD correspondant) est introduit dans la bibliothque de programme (grce une compilation par exemple), on peut alors compiler une instanciation isole par : with P_PILE; ... package PILE_BOOLEENNE is new P_PILE (200, BOOLEAN); ou bien encore (Voir cours E/S) with ADA.TEXT_IO; ... package ENTIER_IO is new ADA.TEXT_IO.INTEGER_IO (T_ENTIER); Lembotement d'units gnriques est possible mais ne doit pas tre rcursif (voir TD rcursivit). Exemple dembotements : generic type T_OBJET is private; procedure DECAL_GAUCHE (A, B, C : in out T_OBJET) is procedure TROC is new ECHANGE_TOUT (T_ELEMENT => T_OBJET); begin TROC (A,B); procedure Decal_Entier is new DECAL_GAUCHE (T_ENTIER) ; TROC (B,C); permet de crer une vraie procdure Decal_Entier end DECAL_GAUCHE; Remarque : le type effectif (sur lexemple T_ENTIER) associ T_OBJET au moment de linstanciation de DECAL_GAUCHE servira aussi linstanciation interne de TROC. Instanciation en cascade Spcification gnrique. Une spcification gnrique commence par le mot cl generic suivi de la liste des paramtres formels gnriques et se termine comme une unit non gnrique (c'est--dire par le end de l'unit). Mais la liste des paramtres, elle, sarrte (on la dit) lun des mots rservs : package, procedure ou function. Soit le schma formel : generic -liste des paramtres gnriques (voir plus loin une tude dtaille) package NOM_DU_PAQUETAGE is -les objets exports end NOM_DU_PAQUETAGE; -- fin de la spcification gnrique Exemple : generic type type type type package PIXEL ABSCISSE ORDONNEE IMAGE LOGICIEL_IMAGE Dbut de la liste des paramtres gnriques is is is is 4 paramtres gnriques

range <>; range <>; range <>; array (ABSCISSE,ORDONNEE) of PIXEL; Le mot package marque la fin de la liste des paramtres gnriques

is

end

-partie visible et partie prive du paquetage LOGICIEL_IMAGE;

D. Feneuille I.U.T. Aix 2001 (Cours n 9 fichier COURS9.DOC) 04/04/01

3 Les paramtres formels de la gnricit sont classs en : paramtres vus comme des valeurs ou des variables. paramtres sous forme de types. paramtres sous-programmes. paramtres paquetages.

Les paramtres gnriques valeurs ou variables .


1) Variables mais vues comme des "constantes" ou des donnes. Ces objets sont considrs comme constants pour l'unit de programme gnrique et peuvent mme avoir une valeur par dfaut. Leur mode de passage est in (videmment) sans qu'il soit besoin de le prciser. Exemple : generic TAILLE NOMBRE NOMBRE_MAX : package P_....... is ........ end P_....... ;

: NATURAL := 200; : in POSITIVE := POSITIVE'LAST; NATURAL;

2) Variables vraies en paramtre (in out obligatoires ; pas de out) Exemple : generic SCORE : in out NATURAL ; package P_JEU is ......... end P_JEU ; Le paramtre effectif "associ" au paramtre formel SCORE (au moment de linstanciation) sera tenu jour tout au long de la porte du paquetage P_JEU instanci.

Les paramtres gnriques sous forme de types.


La possibilit de passer des types en paramtre est l'un des traits les plus remarquables de la gnricit . Dans une unit gnrique, les types passs en paramtres sont videmment formels. Les types gnriques constituent donc des classes de type . On distingue dix catgories : Un type sur lequel on ne possde aucune information est dclar limited private Un type sur lequel on exige au moins l'affectation et la comparaison sera not private Un type discret sera not (<>) (numratifs presque essentiellement) Un type entier sera not range <> Un type entier modulaire sera not mod <> voir cours Un type rel point flottant sera not digits <> numriques Un type rel point fixe binaire sera not delta <> Un type rel point fixe dcimal sera not delta <> digits <> Un type tableau sera not array Un type accs (pointeur) sera introduit par access (voir le cours correspondant n12). Exemples : generic type type type

T_CIRCULAIRE is mod <>; T_INDICE is (<>); T_EURO is delta <> digits <> ;

D. Feneuille I.U.T. Aix 2001 (Cours n 9 fichier COURS9.DOC) 04/04/01

4 type type type type ............ Les types gnriques tableaux peuvent tre contraints ou non contraints . Tableaux gnriques non contraints : generic type T_INDEX is (<>); type T_TABLE is array ............ T_LONGUEUR T_ANGLE T_ENTIER T_ACC_INFO is is is is range <>; digits <>; range <>; access INFO;

-- type discret (T_INDEX range <>) of T_ENTIER;

Le type des lments du tableau peut lui mme tre gnrique : generic type T_INDEX is (<>); type T_ELEMENT is private; type T_TABLEAU is array (T_INDEX range <>) .............

of

T_ELEMENT;

Tableaux gnriques contraints : Les indices sont indiqus par une marque de type discret : sans le " range <> " videmment. generic type type type type .............

T_INDEX T_ELEMENT T_TABLE T_TABLEAU

is is is is

(<>); private; array (T_INDEX) of INTEGER; array (T_INDEX) of T_ELEMENT;

Type gnrique formel et type gnrique effectif (association linstanciation) : Exemple simple : (on travaille ici avec une fonction gnrique et pas un paquetage gnrique) generic type T_DISCRET is (<>); function SUIVANT (X : T_DISCRET) return T_DISCRET; -- spcifications ............... puis plus loin la ralisation : function SUIVANT (X : T_DISCRET) return begin if X = T_DISCRET'LAST then return T_DISCRET'FIRST; else return T_DISCRET'SUCC(X); end if; end SUIVANT; T_DISCRET is -- dfinition

Le paramtre formel T_DISCRET exige que le type effectif soit un type discret ( cause de : is (<>)). Les attributs FIRST et LAST peuvent tre utiliss dans le corps car le type discret les possde. Nous pouvons instancier et crire : function DEMAIN is new SUIVANT(T_JOUR); et DEMAIN(DIMANCHE) donne LUNDI.

D. Feneuille I.U.T. Aix 2001 (Cours n 9 fichier COURS9.DOC) 04/04/01

5 Un type gnrique effectif peut aussi tre un sous-type : function JOUR_OUVRE_SUIV is new SUIVANT(T_JOUR_OUVRABLE); avec subtype T_JOUR_OUVRABLE is T_JOUR range LUNDI..VENDREDI; On obtient JOUR_OUVRE_SUIV(VENDREDI) donne LUNDI. Cest beau non ? ! Autre exemple : Un paramtre gnrique formel peut dpendre d'un type paramtre formel prcdent. C'est souvent le cas pour les tableaux. (ci dessous T_VEC dpend de T_INDICE) : generic type T_INDICE is (<>); type T_FLOTTANT is digits <>; type T_VEC is array (T_INDICE range <>) of T_FLOTTANT; function SOMME (A : T_VEC) return T_FLOTTANT; ................. function RESULTAT begin for SOMME (A : T_VEC) return : T_FLOTTANT := 0.0; T_FLOTTANT is

end

IND in A'RANGE loop RESULTAT := RESULTAT end loop; return RESULTAT; SOMME;

+ A(IND);

L'instanciation et l'utilisation de la fonction SOMME s'effectuent de la faon suivante : procedure TEST is type type type T_JOUR is (LUNDI,....,DIMANCHE); T_REEL is digits 15 ; T_VECTEUR is array (T_JOUR range <> ) of T_REEL;

function SOMME_VECTEUR is new SOMME(T_JOUR,T_REEL,T_VECTEUR); subtype S_VECTEUR is T_VECTEUR (LUNDI..VENDREDI); TABLE : S_VECTEUR; S : T_REEL; begin ............ S := SOMME_VECTEUR(TABLE); ............. end TEST; ici on contraint enfin le tableau !

Remarque : Attention la correspondance entre type gnrique formel et type gnrique effectif. Si on avait crit : type T_VECTEUR is array (CHARACTER range <>) of FLOAT; l'instanciation s'crirait : function SOMME_VECTEUR is new SOMME(CHARACTER,FLOAT,T_VECTEUR);

Paramtres gnriques sous -programmes (fonctions et procdures).


Il est possible de passer des sous-programmes comme paramtres de la gnricit. Ils seront dcrits dans la liste des paramtres de l'unit gnrique et ils seront introduits par le mot cl with.

D. Feneuille I.U.T. Aix 2001 (Cours n 9 fichier COURS9.DOC) 04/04/01

6 Avant Ada 95 les S/P ne pouvaient tre paramtres que des units gnriques . Voyons cela. Soit la fonction INTEGRALE gnrique (notez le with ! dans la liste des paramtres) : generic with function G (X : FLOAT) return FLOAT; function INTEGRALE (A,B : FLOAT) return FLOAT; qui value une fonction formelle comme : un paramtre gnrique fonction Notez bien les deux mots function (pas la mme chose)
1

b a G(x) dx

Pour intgrer une fonction particulire par exemple :

e t * sin(t)dt

On crit d'abord la fonction effective F qui servira instancier la fonction gnrique INTEGRALE : function F (T : FLOAT) return FLOAT is begin return EXP(T) * SIN(T); end F; puis on effectue l'instanciation de la fonction INTEGRALE avec le paramtre effectif F ainsi : function INTEGRER_F is new INTEGRALE (F); et nous obtenons le rsultat en utilisant la fonction instancie INTEGRER_F par exemple en crivant : X := INTEGRER_F(0.0,PI); La spcification du S/P formel peut dpendre de types formels prcdents. Reprenons notre exemple : generic type T_FLOTTANT is digits <>; -- un type rel with function G (X : T_FLOTTANT) return T_FLOTTANT; function INTEGRALE (A,B : T_FLOTTANT) return T_FLOTTANT; La fonction d'intgration s'applique tout type point-flottant (cette classe de type rel sera vue plus tard). type T_REEL is digits 8; function INTEGRER_F is new INTEGRALE(T_REEL,F); -- deux paramtres dinstanciation cette fois Les S/P passs en tant que paramtres gnriques (fonctions ou procdures) permettent de spcifier les oprations disponibles sur les types formels gnriques. Voyons un exemple : On veut gnraliser la fonction gnrique SOMME vue en amont en passant l'oprateur + en paramtre gnrique et en rendant le type des composants plus ouvert . Soit lidentificateur OPERER pour cette nouvelle criture. generic type T_INDICE type T_ITEM type T_VEC with function function OPERER (A :

is (<>); is private; is array (T_INDICE range <> ) of T_ITEM; "+" (X,Y : T_ITEM) return T_ITEM; T_VEC) return T_ITEM;

Depuis les choses se sont amliores ! la nouvelle norme permet de dfinir des pointeurs sur S/P. A revoir ! D. Feneuille I.U.T. Aix 2001 (Cours n 9 fichier COURS9.DOC) 04/04/01

7 L'oprateur "+" a t ajout comme paramtre car T_ITEM est dclar private (type affectation). Peut-on maintenant appliquer la fonction gnrique n'importe quelle opration binaire sur n'importe quel type ? Les instanciation s'criraient : function ADDI_R is new OPERER (T_JOUR,FLOAT,T_VECTEUR,"+"); function PROD_R is new OPERER (T_JOUR,FLOAT,T_VECTEUR,"*");

on souhaite des produits au lieu dadditions

De mme peut-on dfinir les fonctions ADDI_E et PROD_E en remplaant FLOAT par INTEGER ? Ceci ne va pas toujours sans problme ! Voyons la dfinition de la fonction OPERER. Si cette fonction reprend lesprit de la fonction SOMME page 5 soit : function RESULTAT begin for OPERER (A : T_VEC) : T_ITEM := 0.0; return T_ITEM is Ici avec 0.0 il y a un gros problme suivant le type numrique !

end

IND in A'RANGE loop RESULTAT := RESULTAT + A(IND); end loop; return RESULTAT; OPERER;

Revoyons la liste des paramtres formels pour mmoire : generic type T_INDICE is (<>); type T_ITEM is private; type T_VEC is array (T_INDICE range <> ) of T_ITEM; with function "+" (X,Y : T_ITEM) return T_ITEM; function OPERER (A : T_VEC) return T_ITEM; T_INDICE est discret donc lcriture ARANGE est sans ambigut. Lopration symbolise formellement par le + est une opration binaire entre deux T_ITEM elle sera (suivant linstanciation) soit un vrai + ou alors un * (voir les deux instanciations proposes). L encore pas de problme. Par contre laffectation avec la valeur 0.0 est ose . Dabord on imagine ce que donnerait la fonction instancie PROD avec une telle initialisation ! Il est clair quil faut initialiser RESULTAT avec la valeur lment neutre pour lopration donc 0 ou 0.0 (suivant le type) pour laddition et 1 ou 1.0 pour le produit. Donc mme sil ny a pas deux oprateurs distincts on est oblig de connatre la valeur dinitialisation suivant le type des lments du vecteur. Rappelons que private ne dfinit rien de prcis (type affectation : affectation et galit seulement) ! Pour rsoudre notre problme il faut absolument ajouter un cinquime paramtre gnrique quil faudra instancier correctement suivant le type des composants du vecteur et suivant le signe de lopration. (page suivante). Remarque encore : Dans la partie gnrique nous avons dclar la fonction return T_ITEM;

with function "+" (X,Y : T_ITEM)

Dans ce cas le paramtre effectif "+" ne peut tre omis au cours de l'opration d'instanciation bien que lon instancie "+" avec "+". Le "*" ne peut tre omis non plus mais cela est vident ! En crivant maintenant (notez le is <> en plus) : with function "+" (X,Y: T_ITEM) return T_ITEM is <>; en plus!

alors le paramtre effectif "+" peut tre omis au cours de l'opration d'instanciation si lon souhaite faire des additions (mais il faudra mettre le "*" videmment si lon souhaite faire des produits) !

D. Feneuille I.U.T. Aix 2001 (Cours n 9 fichier COURS9.DOC) 04/04/01

8 Do les critures : generic Un paramtre de plus ! type T_INDICE is (<>); type T_ITEM is private; type T_VEC is array (T_INDICE range <> ) of T_ITEM; ELEM_NEUTRE : T_ITEM; with function "+" (X,Y : T_ITEM) return T_ITEM is <>; function OPERER (A : T_VEC) return T_ITEM; ................ function RESULTAT begin for OPERER (A : T_VEC) return : T_ITEM := ELEM_NEUTRE; T_ITEM is Ici cest correct car le private admet laffectation

end

IND in A'RANGE loop RESULTAT := RESULTAT + A(IND); end loop; return RESULTAT; OPERER;

Et quelques instanciations : function ADD_V_ENTIER is new OPERER (T_JOUR,T_ENTIER,0,T_V......); -- + omis ! function ADD_V_REEL is new OPERER (T_JOUR,FLOAT,0.0,T_V......); -- + omis ! function PROD_V_REEL is new OPERER (T_JOUR,FLOAT,1.0,T_V......, * ); function PROD_V_ENTIER is new OPERER (T_JOUR,T_ENTIER ,1,T_V......, * ); Remarque : pour chaque instanciation le vecteur marqu ci-dessus T_V...... devra tre dclar comme compatible avec les paramtres effectifs qui le prcdent ! Un autre exemple de ralisation de corps (qui, celui-l, ne pose pas de problme!) : La fonction INTEGRALE calcule l'intgrale d'une fonction entre deux valeurs A et B (admise plus haut). Voici une ralisation possible du corps. La fonction intgrer G constitue un paramtre gnrique. Une amlioration intressante de cette fonction sera vue en TP numrique. generic type T_FLOTTANT is digits <>; with function G (X : T_FLOTTANT) return T_FLOTTANT; function INTEGRALE (A,B : in T_FLOTTANT) return T_FLOTTANT; .. function INTEGRALE (A,B : in T_FLOTTANT) return T_FLOTTANT is SOMME,DELTAX : T_FLOTTANT; NB_PAS : POSITIVE := 100; begin SOMME := 0.0; DELTAX := (B-A)/T_FLOTTANT(NB_PAS); for IND in 1..NB_PAS-1 loop SOMME := SOMME + G(A + T_FLOTTANT(IND) * DELTAX); end loop; return SOMME + DELTAX * (G(A) + G(B)) / 2.0 ; end INTEGRER; Remarque : Ada permet aussi les paramtres gnriques non contraints ainsi : type T_NON_CONTRAINT (<>) is private; A revoir au cours n11 avec les fichiers squentiels !

D. Feneuille I.U.T. Aix 2001 (Cours n 9 fichier COURS9.DOC) 04/04/01

Les paramtres gnriques sous forme de paquetage.

Ada permet aussi un paquetage gnrique comme paramtre dun autre paquetage gnrique. Ainsi : generic type T_NUMERIQUE is private; ELEM_NEUTRE : T_NUMERIQUE; ........... package P_OUTILS_NUMERIQUE is ....... contient quelques outils simples end P_OUTILS_NUMERIQUE; ............... on a dfinit ainsi un premier paquetage gnrique P_OUTILS_NUMERIQUE qui permet des oprations sur un type numrique abstrait . On dsire maintenant crire un paquetage P_MATRICE (lui aussi gnrique) mais plus amb itieux qui utiliserait le premier paquetage P_OUTILS_NUMERIQUE dj ralis. generic ....... with package P_OUTILS is new P_OUTILS_NUMERIQUE(<>); ......... Le paramtre gnrique est un .......... paquetage gnrique. P_OUTILS package P_MATRICE is sera une instanciation de ........ P_OUTILS_NUMERIQUE end P_MATRICE; avec package P_OUTILS_FLOAT is new P_OUTILS_NUMERIQUE(FLOAT,0.0,....); on instancie dabord le premier paquetage avec des FLOAT. Puis avec : package P_MATRICE_FLOAT is new P_MATRICE (.....,P_OUTILS_FLOAT,....); on instancie le deuxime paquetage. Notez quil faut instancier le deuxime avec, comme paramtre effectif, une instance du premier paquetage. De mme : avec package P_OUTILS_ENTIER is new P_OUTILS_NUMERIQUE(T_ENTIER,0,....); on peut instancier avec des entiers : package P_MATRICE_ENTIER is new P_MATRICE (.....,P_OUTILS_ENTIER,....); On a ainsi encore largi la puissance de Ada pour la rutilisation par le biais de la gnricit. Remarques : On verra de belles applications de la gnricit par la suite cours sur les E/S (cours n11). et plus loin dans ce cours n9 avec les sous paquetages gnriques de ADA.TEXT_IO : INTEGER_IO, FLOAT_IO, FIXED_IO, ENUMERATION_IO, MODULAR_IO, DECIMAL_IO. Les paquetages de Ada qui sont trs utiles (car gnriques) sont dcouvrir (ditez) notamment : Generic_Bounded_Length sous paquetage de Ada.Strings.Bounded (vu en TD 12A et B) ainsi que pour gnrer des nombres alatoires : Ada.Numerics.Discrete_Random. Et enfin pour tout ce qui est calculs numriques : Ada.Numerics.Generic_Elementary_Functions permettant les fonctions mathmatiques classiques (cosinus, sinus, tangente, arc tangente etc.). Lancez vous ! Osez la gnricit cest--dire pensez (ds la conception) la gnricit vous rcuprerez plus tard votre investissement !

D. Feneuille I.U.T. Aix 2001 (Cours n 9 fichier COURS9.DOC) 04/04/01

10

Les fils gnriques.


La notion de hirarchie de paquetages (vue au cours n7) peut videmment se conjuguer avec le concept de gnricit. Puisque la gnricit permet la construction de modules instanciables il tait intressant de pouvoir lui associer cette autre proprit de construction hirarchique pour une puissance dutilisation renforce. Tout paquetage pre (mme non gnrique) peut avoir des fils gnriques. Si le pre nest pas gnrique alors un fils gnrique est instanci traditionnellement aux endroits o il est visible (avec with). Si le pre est gnrique alors tous ses fils seront obligatoirement gnriques et nots comme tels (mme avec une liste vide de paramtres sil ne faut pas en rajouter). Linstanciation dun fils peut avoir lieu lintrieur de la hirarchie familiale sans problme. Si linstanciation est externe (par un utilisateur par exemple) alors ce ne peut tre que dune instance de son pre.

Exemple (reprenons le paquetage P_COMPLEXE cours n7) et rendu gnrique avec un type rel flottant : generic type T_FLOTTANT is digits <> ; package P_COMPLEXE is type T_NOMBRE_COMPLEXE is private; function "+" (C1,C2 : T_NOMBRE_COMPLEXE) return T_NOMBRE_COMPLEXE; function "-" (C1,C2 : T_NOMBRE_COMPLEXE) return T_NOMBRE_COMPLEXE; function "*" (C1,C2 : T_NOMBRE_COMPLEXE) return T_NOMBRE_COMPLEXE; function "/" (C1,C2 : T_NOMBRE_COMPLEXE) return T_NOMBRE_COMPLEXE; procedure LIRE (C : out T_ NOMBRE_COMPLEXE); procedure ECRIRE (C : in T_ NOMBRE_COMPLEXE); private type T_NOMBRE_COMPLEXE is record PARTIE_REELLE : T_FLOTTANT; PARTIE_IMAGINAIRE : T_FLOTTANT; end record; end P_COMPLEXE; lutilisation avec le type prdfini FLOAT est facile (rappel) : package P_COMPLEXE_FLOAT is new P_COMPLEXE(FLOAT) ; et cest tout. Si nous souhaitons amliorer, pour une utilisation plus pointue, le paquetage P_COMPLEXE on crit un fils : generic Liste gnrique vide dans ce cas ! Rien rajouter !

package P_COMPLEXE.ELARGI is function Conjugue (X : T_Complexe) return T_Complexe; function Argument (X : T_Complexe) return T_FLOTTANT; function Module (X : T_Complexe) return T_FLOTTANT; end P_COMPLEXE.ELARGI; Si lon souhaite utiliser une instance de ce paquetage fils P_COMPLEXE.ELARGI il faut absolument dabord instancier le pre P_COMPLEXE par exemple avec le type FLOAT : package P_COMPLEXE_FLOAT is new P_COMPLEXE(FLOAT) ; puis instancier le fils gnrique qui se nomme maintenant P_COMPLEXE_FLOAT.ELARGI (notez le) par exemple ainsi : package P_ELARGI_FLOAT is new P_COMPLEXE_FLOAT.ELARGI ; Notez linstanciation sans paramtre effectif puisquil ny a pas de nouveau paramtre formel. Si la liste navait pas t vide on aurait crit : package P_ELARGI_FLOAT is new P_COMPLEXE_FLOAT.ELARGI(param_effectifs) ;

D. Feneuille I.U.T. Aix 2001 (Cours n 9 fichier COURS9.DOC) 04/04/01

11

Application de la gnricit.
Retour sur ADA.TEXT_IO (voir cours 5 bis et ce nest pas fini!) Des rudiments dentres-sorties simples (puiss dans le paquetage ADA.TEXT_IO) ont dj t voqus dans le cours n 5 bis (pour viter dutiliser P_E_SORTIE). Nous allons complter nos connaissances sur ce paquetage en tudiant les sous paquetages qui composent lessentiel de son corps. Ces 6 paquetages : INTEGER_IO, FLOAT_IO, FIXED_IO, ENUMERATION_IO, DECIMAL_IO et MODULAR_IO ont la proprit dtre gnriques. Cependant nous ne nous intresserons ici quaux sous-programmes qui permettent les changes clavier cran seulement. Les E/S sur fichiers textes puis dans dautres paquetages autres que ADA.TEXT_IO sur fichiers squentiels et enfin sur fichiers directs sont tudis dans un autre support. Il est conseill ceux qui le peuvent dditer lannexe A.10.1 du manuel de rfrence pour plus de lisibilit. Le sous-paquetage INTEGER_IO. Aprs les sous-programmes non gnriques on trouve (polycopi paquetages ) dans le paquetage ADA.TEXT_IO les lignes suivantes : generic type NUM is range <>; package INTEGER_IO is Les deux lignes marques ... concernent DEFAULT_WIDTH : FIELD := NUMWIDTH; les GET et PUT sur fichiers textes. DEFAULT_BASE : NUMBER_BASE := 10; ..... procedure GET(ITEM : out NUM; WIDTH : in FIELD := 0); ..... procedure PUT(ITEM : in NUM; WIDTH : in FIELD := DEFAULT_WIDTH; BASE : in NUMBER_BASE := DEFAULT_BASE); procedure GET(FROM : in STRING; ITEM : out NUM; LAST : out POSITIVE); procedure PUT(TO : out STRING; ITEM : in NUM; BASE : in NUMBER_BASE := DEFAULT_BASE); end INTEGER_IO;

Les deux premires procdures ci-dessus permettent : des saisies clavier (avec GET) ou des affichages cran (avec PUT) dinstances de type gnrique NUM ( type entier cause du range <>). Les deux dernires (intressantes ) permettent dextraire lentier ITEM dun STRING (avec GET) ou de convertir en caractres dans un STRING lentier ITEM (avec PUT) elles ne sont pas utilises en gnral et cest bien dommage ! Aussi aprs avoir instanci un paquetage vrai avec un type entier (T_COMPTEUR par exemple) on peut mettre en uvre les E/S sur ce type. Exemple aprs : package E_S_COMPTEUR is new ADA.TEXT_IO.INTEGER_IO(T_COMPTEUR); les oprations : E_S_COMPTEUR.GET et E_S_COMPTEUR.PUT sont disponibles. Remarques : On peut utiliser GET et PUT sans prfixer si lon a utilis la clause use E_S_COMPTEUR. La procdure GET (clavier) nest pas valide pour autant et il est prfrable de linclure dans une boucle loop avec traitement dexception et nous voil ramen notre vieille connaissance de lecture valide dun type discret qui est bton . Vue cours n1 (paquetage P_E_SORTIE), cours n3 (instruction bloc), cours n5 (procdure LIRE), cours n5 bis (E/S simples), cours n8 (exception) etc. PUT est intressant quand on utilise son formatage . GET et PUT dans un String sont trs intressantes ( voir).

D. Feneuille I.U.T. Aix 2001 (Cours n 9 fichier COURS9.DOC) 04/04/01

12 Le paquetage ENUMERATION_IO. Dans le mme ordre dide on trouve aussi dans le paquetage ADA.TEXT_IO ( la fin) le sous-paquetage ENUMERATION_IO. Soit : generic type ENUM is (<>); package ENUMERATION_IO is DEFAULT_WIDTH : FIELD := ENUMWIDTH; DEFAULT_SETTING : TYPE_SET := UPPER_CASE; ..... procedure GET(ITEM : out ENUM); ..... procedure PUT(ITEM : in ENUM; WIDTH : in FIELD := DEFAULT_WIDTH; SET : in TYPE_SET := DEFAULT_SETTING); procedure GET(FROM : in STRING; ITEM : out ENUM; LAST : out POSITIVE); procedure PUT(TO : out STRING; ITEM : in ENUM; SET : in TYPE_SET := DEFAULT_SETTING); end ENUMERATION_IO; Remarques : Il faut instancier avec un type numratif (par exemple T_JOUR). GET ne nous dispense pas de la validation et on peut lui prfrer notre vieille connaissance de lecture de type discret (car les numratifs sont discrets)! Seules en fait, comme prcdemment, les deux dernires procdures en relation avec les STRING sont intressantes. Ainsi que le premier PUT pour son formatage. Le paquetage FLOAT_IO. Ce paquetage gnrique permet des entres-sorties sur tout type rel (virgule flottante ou digits) construit ou prdfini (comme FLOAT). Ces types numriques seront tudis prochainement (aprs le cours n 11). FORE signifie partie entire du nombre. AFT signifie partie dcimale (aprs le point dcimal). EXP (non nul) implique la notation scientifique normalise. EXP (nul) implique lcriture normale non scientifique. generic type NUM is digits <>; package FLOAT_IO is DEFAULT_FORE : FIELD := 2; DEFAULT_AFT : FIELD := NUMDIGITS - 1; DEFAULT_EXP : FIELD := 3; ..... procedure GET(ITEM : out NUM; WIDTH : in FIELD := 0); ..... procedure PUT(ITEM : in NUM; FORE : in FIELD := DEFAULT_FORE; AFT : in FIELD := DEFAULT_AFT; EXP : in FIELD := DEFAULT_EXP); procedure GET(FROM : in STRING; ITEM : out NUM; LAST : out POSITIVE); procedure PUT(TO : out STRING; ITEM : in NUM; AFT : in FIELD := DEFAULT_AFT; EXP : in FIELD := DEFAULT_EXP); end FLOAT_IO; Le paquetage FIXED_IO. Ce paquetage gnrique permet des entres-sorties sur tout type rel (virgule fixe ou delta) construit ou prdfini (comme DURATION). Ces types numriques seront tudis plus tard en mme temps que les rels virgule flottante (digits). FORE signifie partie entire du nombre. AFT signifie partie fractionnaire (aprs le point dcimal). EXP (non nul) implique notation scientifique normalise. EXP (nul) implique lcriture normale non scientifique.

D. Feneuille I.U.T. Aix 2001 (Cours n 9 fichier COURS9.DOC) 04/04/01

13 generic type NUM is delta <>; package FLOAT_IO is DEFAULT_FORE : FIELD := NUMFORE; DEFAULT_AFT : FIELD := NUMAFT; DEFAULT_EXP : FIELD := 0; ..... procedure GET(ITEM : out NUM; WIDTH : in FIELD := 0); ..... procedure PUT(ITEM : in NUM; FORE : in FIELD := DEFAULT_FORE; AFT : in FIELD := DEFAULT_AFT; EXP : in FIELD := DEFAULT_EXP); procedure GET(FROM : in STRING; ITEM : out NUM; LAST : out POSITIVE); procedure PUT(TO : out STRING; ITEM : in NUM; AFT : in FIELD := DEFAULT_AFT; EXP : in FIELD := DEFAULT_EXP); end FLOAT_IO; Le paquetage MODULAR_IO. generic type NUM is mod <>; package MODULAR_IO is DEFAULT_WIDTH : FIELD := NUMWIDTH; DEFAULT_BASE : NUMBER_BASE := 10; ..... procedure GET(ITEM : out NUM; WIDTH : in FIELD := 0); ..... procedure PUT(ITEM : in NUM; WIDTH : in FIELD := DEFAULT_WIDTH; BASE : in NUMBER_BASE := DEFAULT_BASE); procedure GET(FROM : in STRING; ITEM : out NUM; LAST : out POSITIVE); procedure PUT(TO : out STRING; ITEM : in NUM; BASE : in NUMBER_BASE := DEFAULT_BASE); end MODULAR_IO; totalement identique INTEGER_IO mais, bien sr, il traite des entiers modulaires. Le paquetage DECIMAL_IO (identique FIXED_IO) sera tudi avec un cours associ il utilise le type dit dcimal ou delta-digits. Remarque : On a recommand lutilisation de la lecture Get et lcriture Put dun numrique par le biais dun String. Lintrt ne parat pas toujours vident. Voici peut tre un exemple convaincant : function Jour_Courant return String is Top : Time := Clock; La_Date : String (1..10) := " / / " ; begin Put (La_Date(1..2), Day(Top)) ; Put (La_Date(4..5), Month(Top)) ; Put (La_Date(7..10), Year(Top)) ; return La_Date; end Jour_Courant; Bien sr il faut avoir voqu le paquetage Calendar (pour Time, Clock, Day, Month et Year) et il faut avoir instanci un paquetage vrai de Integer_IO pour faire les Put ! Pour le Get imaginez des lectures de plusieurs valeurs numriques dans une ligne de texte.

D. Feneuille I.U.T. Aix 2001 (Cours n 9 fichier COURS9.DOC) 04/04/01

14

Je retiens n3
Quelques termes, informations ou conseils retenir aprs le cours n 9 Ada (semaines 5, 6). Cette fiche fait suite aux fiches je retiens n1 et n2 vues prcdemment.

Le type article est, comme le type tableau, un type composite (ou compos). Par contre les composants dun type article ne sont pas forcment du mme type alors quils le sont forcment pour les tableaux. Les composants dun tableau sont reprs et slectionnables grce un indice de type discret. Les composants dun type article sont reprables et slectionnables grce des identificateurs de champ. Si les tableaux pouvaient tre anonymes ou muets (mais ce nest pas recommand!) les articles ne le peuvent pas. Un tableau ne peut pas tre anonyme sil est composant darticle. Comme pour les tableaux le mcanisme de passage de paramtres dun type article nest pas dfini par la norme. Si un type article na pas de discriminant avec une expression par dfaut alors tous les objets (ou instances) de ce type doivent tre contraints. Le discriminant dun article non contraint ne peut tre modifi que par affectation globale de tout larticle. Toute partie variante darticle doit apparatre comme dernier composant darticle (avec case). Les discriminants servent souvent pour grer des bornes variables de tableaux ou pour grer des parties variantes. Les variables dclares dans la partie spcifications dun paquetage sont des variables globales trs persistantes! Une unit de bibliothque doit tre compile aprs toutes les units voques avec with (vident!). Un corps (body) de paquetage doit tre compil seulement aprs la spcification correspondante! Une spcification de paquetage et son corps forment un tout logique indissociable. Ne pas confondre les attributs LENGTH et LAST. Pour que leur valeur soit identique il faut que le type dindice du tableau soit NATURAL et que lattribut FIRST donne 1. Pas forcment courant! Les sous programmes (procdure et fonction) gnriques ont toujours une spcification et un corps spars . Soignez les modes des paramtres formels : in, out ou in out. Chacun exprime une smantique importante il faut la respecter. Prescrire les variables globales systmatiquement. Sinon danger! Pour les procdures avec paramtres formels out et pour les fonctions il est recommand de crer une variable locale jouant le rle du rsultat dans le corps du sous programme. Le transfert final seffectue la fin seulement. PUT_LINE et GET_LINE (de Text_Io) sont uniquement rservs aux objets de type STRING. Les sous-programmes gnriques ne peuvent pas tre surchargs. Mais leurs instances peuvent ltre. On ne peut utiliser use avec un paquetage gnrique. Un peu de rflexion nous dmontre pourquoi! Le mode out nexiste pas pour les paramtres gnriques. Seulement in ou in out. Attention aux variables non initialises. Pour viter les CONSTRAINT_ERROR rflchir aux contraintes dindice sur les tableaux, ainsi quaux valeurs extrmes des objets discrets (entiers et numratifs). Les exceptions paraissent simples comprendre .. Attention pige! Ne pas en abuser. Il est prfrable de grer ses propres exceptions. Evitez les prdfinies. Le traite exception mrite une attention soigne. Attention aux paramtres out ou in out quand une exception est traite. Mme problme dans une fonction. Editez les fichiers chaine.doc, rationnel.doc, pragma.doc. Etudiez avec AdaGide (ou le polycopi paquetages ) : Ada.Exceptions, Ada.Strings.Bounded, Ada.Io_Exception.

D. Feneuille I.U.T. Aix 2001 (Cours n 9 fichier COURS9.DOC) 04/04/01

Vous aimerez peut-être aussi