Les unités génériques
Une unité générique est une unité de programme étant soit un sous-programme générique, soit un paquet générique. Une unité générique est un modèle, paramétré ou non, à partir duquel des sous-programmes ou paquets correspondants (non génériques) peuvent être obtenus. Les unités de programme résultantes sont dites instances de l'unité générique d'origine.
Une unité générique est déclarée par une déclaration générique. Cette forme de déclaration comporte une partie formelle générique déclarant tous les paramètres formels génériques. Une instance d'une unité générique est obtenue à la suite d'une instanciation générique avec des paramètres réels génériques appropriés pour les paramètres formels génériques. Une instance d'un sous-programme générique est un sous-programme. Une instance d'un paquet générique est un paquet.
Les unités génériques sont des modèles. En tant que modèles, elles n'ont pas les propriétés spécifiques à leurs homologues non génériques. Par exemple, un sous-programme générique peut être instancié mais ne peut pas être appelé. En revanche, l'instance d'un sous-programme générique est un sous-programme non générique; par conséquent, cette instance peut être appelée mais ne peut pas être utilisée pour produire d'autres instances.
Les déclarations génériques
Une déclaration générique déclare une unité générique, étant soit un sous-programme générique, soit un paquet générique. Une déclaration générique comprend une partie formelle générique déclarant tous les paramètres formels génériques. Un paramètre formel générique peut être un objet; en variante (contrairement à un paramètre d'un sous-programme), il peut être un type ou un sous-programme.
declaration_generique ::= specification_generique; specification_generique ::= partie_formelle_generique specification_du_sous_programme | partie_formelle_generique specification_du_paquet partie_formelle_generique ::= generic [declaration_de_parametre_generique] declaration_de_parametre_generique ::= liste_identifiant : [in [out]] marque_type [:= expression]; | type identifier is definition_de_type_generique; | declaration_de_type_prive | with specification_du_sous_programme [is nom]; | with specification_du_sous_programme [is <>]; definition_de_type_generique ::= (<>) | intervalle <> | chiffres <> | delta <> | definition_du_type_de_tableau | définition_du_type_d_acces |
Les termes objet formel générique (ou simplement objet de format), type formel générique (ou simplement type de format) et sous-programme formel générique (ou simplement sous-programme de format) sont utilisés pour désigner les paramètres formels génériques correspondants.
La seule forme d'indication de sous-type autorisée dans une partie formelle générique est une marque de type (c'est-à-dire que l'indication de sous-type ne doit pas inclure de contrainte explicite). Le désignateur d'un sous-programme générique doit être un identifiant.
En dehors de la spécification et du corps d'une unité générique, le nom de cette unité de programme désigne l'unité générique. En revanche, dans la région déclarative associée à un sous-programme générique, le nom de cette unité de programme désigne le sous-programme obtenu par l'instanciation actuelle de l'unité générique. De même, dans la région déclarative associée à un paquet générique, le nom de cette unité de programme désigne le paquet obtenu par l'instanciation actuelle.
L'élaboration d'une déclaration générique n'a aucun autre effet.
Exemples de parties de format génériques :
- generic -- sans paramètre
-
- generic
- SIZE : NATURAL; -- objet formel
-
- generic
- LENGTH : INTEGER := 200; -- objet formel avec une expression par défaut
- AREA : INTEGER := LENGTH*LENGTH; -- objet formel avec une expression par défaut
-
- generic
- type ITEM is private; -- type formel
- type INDEX is (<>); -- type formel
- type ROW is array(INDEX range <>) of ITEM; -- type formel
- with function "<"(X, Y : ITEM) return BOOLEAN; -- sous-programme formel
Exemples de déclarations génériques déclarant des sous-programmes génériques :
Exemple de déclaration générique déclarant un paquet générique :
Remarques : Dans un sous-programme générique, le nom de cette unité de programme agit comme le nom d'un sous-programme. Ce nom peut donc être surchargé et il peut apparaître dans un appel récursif de l'instanciation courante. Pour la même raison, ce nom ne peut pas apparaître après le mot réservé new dans une instanciation générique (récursive).
Une expression apparaissant dans une partie formelle générique est soit l'expression par défaut d'un objet formel générique de mode in, soit un constituant d'un nom d'entrée donné comme nom par défaut pour un sous-programme formel, soit l'expression par défaut d'un paramètre d'un sous-programme formel. Les expressions par défaut pour les objets formels génériques et les noms par défaut pour les sous-programmes formels ne sont évalués que pour les instanciations génériques utilisant de telles valeurs par défaut. Les expressions par défaut pour les paramètres des sous-programmes formels ne sont évaluées que pour les appels des sous-programmes formels utilisant de telles valeurs par défaut. (Les règles de visibilité habituelles s'appliquent à tout nom utilisé dans une expression par défaut : l'entité désignée doit donc être visible à la place de l'expression.)
Ni les paramètres formels génériques ni leurs attributs ne sont autorisés à être des constituants d'expressions statiques.
Objets formels génériques
La première forme de déclaration de paramètre générique déclare des objets formels génériques. Le type d'un objet formel générique est le type de base du type désigné par la marque de type donnée dans la déclaration de paramètre générique. Une déclaration de paramètre générique avec plusieurs identifiants est équivalente à une séquence de déclarations de paramètres génériques simples.
Un objet formel générique a un mode étant soit in, soit in out. En l'absence d'indication de mode explicite dans une déclaration de paramètre générique, le mode in est supposé ; sinon, le mode est celui indiqué. Si une déclaration de paramètre générique se termine par une expression, l'expression est l'expression par défaut du paramètre formel générique. Une expression par défaut n'est autorisée que si le mode est in (que ce mode soit indiqué explicitement ou implicitement). Le type d'une expression par défaut doit être celui du paramètre formel générique correspondant.
Un objet formel générique de mode in est une constante dont la valeur est une copie de la valeur fournie comme paramètre générique actuel correspondant dans une instanciation générique. Le type d'un objet formel générique de mode in ne doit pas être un type limité; le sous-type d'un tel objet formel générique est le sous-type désigné par la marque de type donnée dans la déclaration de paramètre générique.
Un objet formel générique de mode in out est une variable et désigne l'objet fourni comme paramètre générique actuel correspondant dans une instanciation générique. Les contraintes s'appliquant à l'objet formel générique sont celles du paramètre générique actuel correspondant.
Remarque : les contraintes s'appliquant à un objet formel générique de mode in out sont celles du paramètre générique actuel correspondant (et non celles impliquées par la marque de type apparaissant dans la déclaration du paramètre générique). Dans la mesure du possible (pour éviter toute confusion), il est recommandé d'utiliser le nom d'un type de base pour la déclaration d'un tel objet formel. Si, toutefois, le type de base est anonyme, il est recommandé d'utiliser le nom du sous-type défini par la déclaration de type pour le type de base.
Types formels génériques
Une déclaration de paramètre générique incluant une définition de type générique ou une déclaration de type privé déclare un type formel générique. Un type formel générique désigne le sous-type fourni comme paramètre actuel correspondant dans une instanciation générique (d). Cependant, au sein d'une unité générique, un type formel générique est considéré comme distinct de tous les autres types (formels ou non formels). La forme de contrainte applicable à un type formel dans une indication de sous-type dépend de la classe du type comme pour un type non formel.
La seule forme d'intervalle discrète autorisée dans la déclaration d'un type de tableau formel générique (contraint) est une marque de type.
La partie discriminante d'un type privé formel générique ne doit pas inclure d'expression par défaut pour un discriminant. (Par conséquent, une variable déclarée par une déclaration d'objet doit être contrainte si son type est un type formel générique avec des discriminants.)
Dans la déclaration et le corps d'une unité générique, les opérations disponibles pour les valeurs d'un type formel générique (en dehors de toute opération supplémentaire spécifiée par un sous-programme formel générique) sont déterminées par la déclaration de paramètre générique pour le type formel :
- Pour une déclaration de type privé (en particulier, l'affectation, l'égalité et l'inégalité sont disponibles pour un type privé à moins qu'il ne soit limité).
- Pour une définition de type tableau (par exemple, elles incluent la formation de composants indexés et de tranches).
- Pour une définition de type accès (par exemple, des allocateurs peuvent être utilisés).
Les quatre formes de définition de type générique dans lesquelles une boîte apparaît (c'est-à-dire le délimiteur composé <>) correspondent aux principales formes suivantes de type scalaire :
- Types discrets : (<>) Les opérations disponibles sont les opérations communes aux types énumération et entier.
- Types entiers : intervalle <> : Les opérations disponibles sont les opérations des types entiers.
- Types à virgule flottante : chiffres <> : Les opérations disponibles sont celles de types réels.
- Types à virgule fixe : delta <> : Les opérations disponibles sont celles définies réels sans exposant.
Dans tous les cas (a) à (f) ci-dessus, chaque opération implicitement associée à un type formel (c'est-à-dire autre qu'une opération spécifiée par un sous-programme formel) est implicitement déclarée à la place de la déclaration du type formel. Il en va de même pour un type formel à virgule fixe, à l'exception des opérateurs multiplicateurs fournissant un résultat de type universal-fixed, puisque ces opérateurs spéciaux sont déclarés dans le paquet STANDARD.
Pour une instanciation de l'unité générique, chacune de ces opérations est l'opération de base correspondante ou l'opérateur prédéfini du type actuel correspondant. Pour un opérateur, cette règle s'applique même si l'opérateur a été redéfini pour le type actuel ou pour un type parent du type actuel.
Exemples de types formels génériques :
- type ITEM is private;
- type BUFFER(LENGTH : NATURAL) is limited private:
-
- type ENUM is (<>);
- type INT is range <>;
- type ANGLE is delta <>;
- type MASS is digits <>;
-
- type TABLE is array (ENUM) of ITEM;
Exemple d'une partie formelle générique déclarant un type entier formel :
- generic
- type RANK is range <>;
- FIRST : RANK := RANK'FIRST;
- SECOND : RANK := FIRST + 1; -- l'opérateur "+" de type RANK
Sous-programmes formels génériques
Une déclaration de paramètre générique incluant une spécification de sous-programme déclare un sous-programme formel générique.
Deux formes alternatives de valeurs par défaut peuvent être spécifiées dans la déclaration d'un sous-programme formel générique. Dans ces formes, la spécification du sous-programme est suivie du mot réservé is et soit d'une boîte, soit du nom d'un sous-programme ou d'une entrée.
Un sous-programme formel générique désigne le sous-programme, le littéral d'énumération ou l'entrée fourni comme paramètre réel générique correspondant dans une instanciation générique.
Exemples de sous-programmes formels génériques :
Remarques : Les contraintes qui s'appliquent à un paramètre d'un sous-programme formel sont celles du paramètre correspondant dans la spécification du sous-programme réel correspondant (et non celles impliquées par la marque de type correspondante dans la spécification du sous-programme formel). Une remarque similaire s'applique au résultat d'une fonction. Dans la mesure du possible (pour éviter toute confusion), il est recommandé d'utiliser le nom d'un type de base plutôt que le nom d'un sous-type dans toute déclaration d'un sous-programme formel. Si, toutefois, le type de base est anonyme, il est recommandé d'utiliser le nom du sous-type défini par la déclaration de type.
Le type spécifié pour un paramètre formel d'un sous-programme formel générique peut être n'importe quel type visible, y compris un type formel générique de la même partie formelle générique.
Corps génériques
Le corps d'un sous-programme générique ou d'un paquet générique est un modèle pour les corps des sous-programmes ou paquets correspondants obtenus par des instanciations génériques. La syntaxe d'un corps générique est identique à celle d'un corps générique.
Pour chaque déclaration d'un sous-programme générique, il doit y avoir un corps correspondant.
L'élaboration d'un corps générique n'a d'autre effet que d'établir que ce corps peut désormais être utilisé comme modèle pour l'obtention des instances correspondantes.
Exemple de corps de procédure générique :
Exemple de corps de fonction générique :
Exemple de corps de paquet générique :
- package body ON_VECTORS is
-
- function SUM(A, B : VECTOR) return VECTOR is
- RESULT : VECTOR(A'RANGE); -- le type formel VECTOR
- BIAS : constant INTEGER := B'FIRST - A'FIRST;
- begin
- if A'LENGTH /= B'LENGTH then
- raise LENGTH_ERROR;
- end if;
- for N in A'RANGE loop
- RESULT(N) := SUM(A(N), B(N + BIAS)); -- la fonction formelle SUM
- end loop;
- return RESULT;
- end;
-
- function SIGMA(A : VECTOR) return ITEM is
- TOTAL : ITEM := A(A'FIRST); -- le type formel ITEM
- begin
- for N in A'FIRST + 1 .. A'LAST loop
- TOTAL := SUM(TOTAL, A(N)); -- la fonction formelle SUM
- end loop;
- return TOTAL;
- end;
- end;
Instanciation générique
Une instance d'une unité générique est déclarée par une instanciation générique :
instantiation_generique ::= package identifiant is new nom_du_paquet_generique [piece_generique_actuel]; | procedure identifier is new nom_de_procedure_generique [piece_generique_actuel]; | function designator is new nom_de_fonction_generique [piece_generique_actuel]; piece_generique_actuel ::= (association_generique {, association_generique|) association_generique ::= [parametre_formel_generique =>] parametre_generique_actuel parametre_formel_generique ::= parametre_simple_nom | operateur_symbole parametre_generique_actuel ::= expression | nom_variable | nom_sous_programme | nom_entree | marque_type |
Un paramètre générique actuel explicite doit être fourni pour chaque paramètre formel générique, à moins que la déclaration de paramètre générique correspondante ne spécifie qu'une valeur par défaut peut être utilisée. Les associations génériques peuvent être positionnelles ou nommées, de la même manière que les associations de paramètres des appels de sous-programmes. Si deux ou plusieurs sous-programmes formels ont le même désignateur, les associations nommées ne sont pas autorisées pour les paramètres génériques correspondants.
Chaque paramètre générique actuel doit correspondre au paramètre formel générique correspondant. Une expression peut correspondre à un objet formel de mode in ; un nom de variable peut correspondre à un objet formel de mode in out ; un nom de sous-programme ou un nom d'entrée peut correspondre à un sous-programme formel ; une marque de type peut correspondre à un type formel.
L'instance est une copie de l'unité générique, à l'exception de la partie formelle générique ; ainsi, l'instance d'un paquet générique est un paquet, celle d'une procédure générique est une procédure et celle d'une fonction générique est une fonction. Pour chaque occurrence, au sein de l'unité générique, d'un nom désignant une entité donnée, la liste suivante définit quelle entité est désignée par l'occurrence correspondante au sein de l'instance.
- Pour un nom désignant l'unité générique : L'occurrence correspondante désigne l'instance.
- Pour un nom désignant un objet formel générique de mode in : Le nom correspondant désigne une constante dont la valeur est une copie de la valeur du paramètre générique actuel associé.
- Pour un nom désignant un objet formel générique de mode in out ; Le nom correspondant désigne la variable nommée par le paramètre générique actuel associé.
- Pour un nom désignant un type formel générique : Le nom correspondant désigne le sous-type nommé par le paramètre générique actuel associé (le sous-type actuel).
- Pour un nom désignant un discriminant d'un type formel générique : Le nom correspondant désigne le discriminant correspondant (il doit y en avoir un) du type actuel associé au type formel générique.
- Pour un nom désignant un sous-programme formel générique : le nom correspondant désigne le sous-programme, le littéral d'énumération ou l'entrée nommé par le paramètre actuel générique associé (le sous-programme actuel).
- Pour un nom désignant un paramètre formel d'un sous-programme formel générique : le nom correspondant désigne le paramètre formel correspondant du sous-programme actuel associé au sous-programme formel.
- Pour un nom désignant une entité locale déclarée dans l'unité générique : le nom correspondant désigne l'entité déclarée par la déclaration locale correspondante dans l'instance.
- Pour un nom désignant une entité globale déclarée en dehors de l'unité générique : le nom correspondant désigne la même entité globale.
Des règles similaires s'appliquent aux opérateurs et aux opérations de base : en particulier, les opérateurs formels suivent une règle similaire à la règle (f), les opérations locales suivent une règle similaire à la règle (h) et les opérations pour les types globaux suivent une règle similaire à la règle (i). De plus, si dans l'unité générique un opérateur prédéfini ou une opération de base d'un type formel est utilisé, alors dans l'instance l'occurrence correspondante fait référence à l'opération prédéfinie correspondante du type actuel associé au type formel. Les règles ci-dessus s'appliquent également à toute marque de type ou expression (par défaut) donnée dans la partie formelle générique de l'unité générique.
Pour l'élaboration d'une instanciation générique, chaque expression fournie comme paramètre actuel générique explicite est d'abord évaluée, ainsi que chaque expression apparaissant comme constituant d'un nom de variable ou d'un nom d'entrée fourni comme paramètre actuel générique explicite ; ces évaluations se déroulent dans un ordre n'étant pas défini par le langage. Ensuite, pour chaque association générique omise (le cas échéant), l'expression par défaut ou le nom par défaut correspondant est évalué; ces évaluations sont effectuées dans l'ordre des déclarations de paramètres génériques. Enfin, l'instance générée implicitement est élaborée. L'élaboration d'une instanciation générique peut également impliquer certaines vérifications de contraintes telles que décrites dans les sous-sections suivantes.
L'instanciation générique récursive n'est pas autorisée dans le sens suivant : si une unité générique donnée inclut une instanciation d'une seconde unité générique, alors l'instance générée par cette instanciation ne doit pas inclure une instance de la première unité générique (que cette instance soit générée directement, ou indirectement par des instanciations intermédiaires).
Exemples d'instanciations génériques :
- procedure SWAP is new EXCHANGE(ELEM => INTEGER);
- procedure SWAP is new EXCHANGE(CHARACTER); -- SWAP est surchargé
-
- function SQUARE is new SQUARING (INTEGER); -- "*" de INTEGER utilisé par défaut
- function SQUARE is new SQUARING (ITEM => MATRIX, "*" => MATRIX_PRODUCT);
- function SQUARE is new SQUARING (MATRIX, MATRIX_PRODUCT); -- même que le précédent
-
- package INT_VECTORS is new ON_VECTORS(INTEGER, TABLE, " + ");
Exemples d'utilisation des unités instanciées :
Remarques : l'omission d'un paramètre générique actuel n'est autorisée que s'il existe une valeur par défaut correspondante. Si des expressions par défaut ou des noms par défaut (autres que des noms simples) sont utilisés, ils sont évalués dans l'ordre dans lequel les paramètres formels génériques correspondants sont déclarés.
Si deux sous-programmes surchargés déclarés dans une spécification de paquet générique ne diffèrent que par le type (formel) de leurs paramètres et de leurs résultats, il existe alors des instanciations légales pour lesquelles tous les appels de ces sous-programmes depuis l'extérieur de l'instance sont ambigus. Par exemple :
Règles de correspondance pour les objets formels
Un paramètre formel générique de mode in d'un type donné est mis en correspondance par une expression du même type. Si une unité générique possède un objet formel générique de mode in, une vérification est effectuée pour s'assurer que la valeur de l'expression appartient au sous-type désigné par la marque de type, comme pour une déclaration de constante explicite. L'exception CONSTRAINT_ERROR est levée si cette vérification échoue.
Un paramètre formel générique de mode in out d'un type donné est mis en correspondance par le nom d'une variable du même type. La variable ne doit pas être un paramètre formel de mode out ou une sous-composante de celui-ci. Le nom doit désigner une variable pour laquelle le renommage est autorisé.
Remarques : Le type d'un paramètre formel générique de mode in ne doit pas être un type limité. Les contraintes s'appliquant à un paramètre formel générique de mode in out sont celles du paramètre formel générique correspondant.
Règles de correspondance pour les types privés formels
Un type privé formel générique est mis en correspondance par tout type ou sous-type (le sous-type actuel) satisfaisant les conditions suivantes :
- Si le type formel n'est pas limité, le type actuel ne doit pas être un type limité. (Si, d'un autre côté, le type formel est limité, aucune condition de ce type n'est imposée au type actuel correspondant, pouvant être limité ou non limité.)
- Si le type formel a une partie discriminante, le type actuel doit être un type avec le même nombre de discriminants ; le type d'un discriminant apparaissant à une position donnée dans la partie discriminante du type actuel doit être le même que le type du discriminant apparaissant à la même position dans la partie discriminante du type formel; et le sous-type actuel ne doit pas être contraint. (Si, d'un autre côté, le type formel n'a pas de discriminants, le type réel est autorisé à avoir des discriminants.)
De plus, considérez toute occurrence du nom du type formel à un endroit où ce nom est utilisé comme indication de sous-type sans contrainte. Le sous-type réel ne doit pas être un type de tableau sans contrainte ou un type sans contrainte avec discriminants, si l'une de ces occurrences se trouve à un endroit où une contrainte ou des discriminants par défaut seraient requis pour un type de tableau ou pour un type avec discriminants. La même restriction s'applique aux occurrences du nom d'un sous-type du type formel, et aux occurrences du nom de tout type ou sous-type dérivé, directement ou indirectement, du type formel.
Si une unité générique a un type privé formel avec discriminants, l'élaboration d'une instanciation générique correspondante vérifie que le sous-type de chaque discriminant du type réel est le même que le sous-type du discriminant correspondant du type formel. L'exception CONSTRAINT_ERROR est levée si cette vérification échoue.
Règles de correspondance pour les types scalaires formels
Un type formel générique défini par (<>) correspond à tout sous-type discret (c'est-à-dire tout sous-type d'énumération ou d'entier). Un type formel générique défini par range <> correspond à tout sous-type d'entier. Un type formel générique défini par digits <> correspond à tout sous-type à virgule flottante. Un type formel générique défini par delta <> correspond à tout sous-type à virgule fixe. Aucune autre correspondance n'est possible pour ces types formels génériques.
Règles de correspondance pour les types de tableau formels
Un type de tableau formel est mis en correspondance par un sous-type de tableau actuel satisfaisant aux conditions suivantes :
- Le type de tableau formel et le type de tableau actuel doivent avoir la même dimensionnalité ; le type formel et le sous-type actuel doivent être tous deux contraints ou tous deux non contraints.
- Pour chaque position d'index, le type d'index doit être le même pour le type de tableau actuel que pour le type de tableau formel.
- Le type de composante doit être le même pour le type de tableau actuel que pour le type de tableau formel. Si le type de composante n'est pas un type scalaire, les sous-types de composante doivent être tous deux contraints ou tous deux non contraints.
Si une unité générique possède un type de tableau formel, l'élaboration d'une instanciation correspondante vérifie que les contraintes (le cas échéant) sur le type de composante sont les mêmes pour le type de tableau actuel que pour le type de tableau formel, et de même que pour toute position d'index donnée, les sous-types d'index ou les plages discrètes ont les mêmes limites. L'exception CONSTRAINT_ERROR est levée si cette vérification échoue.
Exemple :
- -- Étant donné le paquet générique
-
- generic
- type ITEM is private;
- type INDEX is (<>);
- type VECTOR is array (INDEX range <>) of ITEM;
- type TABLE is array (INDEX) of ITEM;
- package P is
- ...
- end;
-
- -- et les types
-
- type MIX is array (COLOR range <>) of BOOLEAN;
- type OPTION is array (COLOR) of BOOLEAN;
-
- -- alors MIX peut correspondre à VECTOR et OPTION peut correspondre à TABLE
-
- package R is new P(ITEM => BOOLEAN, INDEX => COLOR,
- VECTOR => MIX, TABLE => OPTION);
-
- -- Notez que MIX ne peut pas correspondre à TABLE et OPTION ne peut pas correspondre à VECTOR
Remarque : pour les règles ci-dessus, si l'un des types d'index ou de composant du type de tableau formel est lui-même un type formel, alors dans l'instance, son nom désigne le sous-type actuel correspondant.
Règles de correspondance pour les types d'accès formels
Un type d'accès formel est mis en correspondance avec un sous-type d'accès réel si le type des objets désignés est le même pour le type actuel que pour le type formel. Si le type désigné n'est pas un type scalaire, les sous-types désignés doivent être tous deux contraints ou tous deux non contraints.
Si une unité générique possède un type d'accès formel, l'élaboration d'une instanciation correspondante vérifie que les contraintes sur les objets désignés sont les mêmes pour le sous-type d'accès réel que pour le type d'accès formel. L'exception CONSTRAINT_ERROR est levée si cette vérification échoue.
Exemple :
- -- les types formels du paquet générique
- generic
- type NODE is private;
- type LINK is access NODE;
- package P is
- ...
- end;
-
- -- peut être associé aux types actuels
-
- type CAR;
- type CAR_NAME is access CAR;
-
- type CAR is
- record
- PRED, SUCC : CAR_NAME;
- NUMBER : LICENSE_NUMBER;
- OWNER : PERSON;
- end record;
-
- -- dans l'instanciation générique suivante
-
- package R is new P(NODE => CAR, LINK => CAR_NAME);
Remarque : pour les règles ci-dessus, si le type désigné est lui-même un type formel, alors dans l'instance, son nom désigne le sous-type actuel correspondant.
Règles de correspondance pour les sous-programmes formels
Un sous-programme formel est mis en correspondance par un sous-programme réel, un littéral d'énumération ou une entrée si les deux ont le même profil de paramètre et de type de résultat; de plus, les modes de paramètre doivent être identiques pour les paramètres formels se trouvant à la même position de paramètre.
Si une unité générique a un sous-programme par défaut spécifié par un nom, ce nom doit désigner un sous-programme, un littéral d'énumération ou une entrée correspondant au sous-programme formel (au sens ci-dessus). L'évaluation du nom par défaut a lieu lors de l'élaboration de chaque instanciation utilisant la valeur par défaut.
Si une unité générique a un sous-programme par défaut spécifié par une boîte, le paramètre réel correspondant peut être omis si un sous-programme, un littéral d'énumération ou une entrée correspondant au sous-programme formel et avec le même désignateur que le sous-programme formel est directement visible à l'endroit de l'instanciation générique ; ce sous-programme, littéral d'énumération ou entrée est alors utilisé par défaut (il doit y avoir exactement un sous-programme, littéral d'énumération ou entrée satisfaisant les conditions précédentes).
Exemple :
- -- étant donné la spécification de fonction générique
-
- generic
- type ITEM is private;
- with function "*" (U, V : ITEM) return ITEM is <>;
- function SQUARING(X : ITEM) return ITEM;
-
- -- et la fonction
-
- function MATRIX_PRODUCT(A, B : MATRIX) return MATRIX;
-
- -- l'instanciation suivante est possible
-
- function SQUARE is new SQUARING(MATRIX, MATRIX_PRODUCT);
-
- -- les instanciations suivantes sont équivalentes
-
- function SQUARE is new SQUARING(ITEM => INTEGER, "*" => "*");
- function SQUARE is new SQUARING(INTEGER, "*");
- function SQUARE is new SQUARING(INTEGER);
Remarques : Les règles de correspondance pour les sous-programmes formels énoncent des exigences similaires à celles s'appliquant aux déclarations de renommage de sous-programmes. En particulier, le nom d'un paramètre du sous-programme formel n'a pas besoin d'être identique à celui du paramètre correspondant du sous-programme actuel; de même, pour ces paramètres, les expressions par défaut n'ont pas besoin de correspondre.
Un sous-programme formel est mis en correspondance par un attribut d'un type si l'attribut est une fonction avec une spécification correspondante. Un littéral d'énumération d'un type donné correspond à une fonction formelle sans paramètre dont le type de résultat est le type donné.
Exemple de paquet générique
L'exemple suivant fournit une formulation possible de piles au moyen d'un paquet générique. La taille de chaque pile et le type des éléments de la pile sont fournis comme paramètres génériques.
- generic
- SIZE : POSITIVE;
- type ITEM is private;
- package STACK is
- procedure PUSH (E : in ITEM);
- procedure POP (E : out ITEM);
- OVERFLOW, UNDERFLOW : exception;
- end STACK;
-
- package body STACK is
-
- type TABLE is array (POSITIVE range <>) of ITEM;
- SPACE : TABLEO .. SIZE);
- INDEX : NATURAL := 0;
-
- procedure PUSH(E : in ITEM) is
- begin
- if INDEX >= SIZE then
- raise OVERFLOW;
- end if;
- INDEX := INDEX + 1;
- SPACE(INDEX) := E;
- end PUSH;
-
- procedure POP(E : out ITEM) is
- begin
- if INDEX = 0 then
- raise UNDERFLOW;
- end if;
- E := SPACE(INDEX);
- INDEX := INDEX - 1;
- end POP;
- end STACK;
Des instances de ce paquet générique peuvent être obtenues comme suit :
Par la suite, les procédures des paquets instanciés peuvent être appelées comme suit :
- STACK_INT.PUSH(N);
- STACK_BOOL.PUSH(TRUE);
Alternativement, une formulation générique du type STACK peut être donnée comme suit (corps du paquet omis) :
- generic
- type ITEM is private;
- package ON_STACKS is
- type STACK(SIZE : POSITIVE) is limited private:
- procedure PUSH (S : in out STACK; E : in ITEM);
- procedure POP (S : in out STACK; E : out ITEM);
- OVERFLOW, UNDERFLOW : exception;
- private
- type TABLE is array (POSITIVE range <>) of ITEM;
- type STACK(SIZE : POSITIVE) is
- record
- SPACE : TABLE(1 .. SIZE);
- INDEX : NATURAL := 0;
- end record;
- end;
Pour utiliser un tel paquet, une instanciation doit être créée et ensuite des piles du type correspondant peuvent être déclarées :