Discussion:
Inherited ambiguous call.
(trop ancien pour répondre)
Blady
2018-06-24 09:09:17 UTC
Permalink
Inherited ambiguous call.

Bonjour,

J'ai une déclaration d'un type objet T et une dérivation DT de ce type
avec une procédure Put surchargée :

1. procedure Test21 is
2.
3. package P is
4. type T is tagged null record;
5. procedure Put (O : T; A : Integer; B : Integer := 0) is null;
6.
7. type DT is new T with null record;
8. procedure Put (O : DT; A : Integer) is null;
9. end P;
10.
11. I : P.DT;
12.
13. begin
14. I.Put (4);
15. end Test21;

La compilation avec GNAT CE 2018 donne :
test21.adb:14:05: ambiguous call to "Put"
test21.adb:14:05: possible interpretation (inherited) at line 7
test21.adb:14:05: possible interpretation at line 8

Ce qui est attendu.
Je tente de masquer de mon programme client de la procédure héritée :

1. procedure Test21 is
2.
3. package P is
4. type T is tagged null record;
5. procedure Put (O : T; A : Integer; B : Integer := 0) is null;
6.
7. type DT is new T with null record;
8. procedure Put (O : DT; A : Integer) is null;
9.
10. private
11. overriding
12. procedure Put (O : DT; A : Integer; B : Integer := 0) is null;
13. end P;
14.
15. I : P.DT;
16.
17. begin
18. I.Put (4);
19. end Test21;

GNAT GPL2017 compile sans broncher mais GNAT CE 2018 envoie :

test21.adb:18:05: ambiguous call to "Put"
test21.adb:18:05: possible interpretation at line 12
test21.adb:18:05: possible interpretation at line 8

Est-ce correct ?
Dans ce cas comment masquer la procédure héritée de mon programme client ?

Merci, Pascal.
J-P. Rosen
2018-06-24 13:48:14 UTC
Permalink
 1. procedure Test21 is
 2.
 3.    package P is
 4.       type T is tagged null record;
 5.       procedure Put (O : T; A : Integer; B : Integer := 0) is null;
 6.
 7.       type DT is new T with null record;
 8.       procedure Put (O : DT; A : Integer) is null;
 9.    end P;
10.
11.    I : P.DT;
12.
13. begin
14.    I.Put (4);
15. end Test21;
On ne peut pas, ni en Ada ni en aucun autre langage (au moins ceux
compilés) "déshériter" un type, et c'est heureux, sinon où irait-on en
cas de liaison dynamique?

Autrement dit, si ton type D hérite visiblement de T, tu es tenu par le
contrat de T, et donc par sa procédure Put. Ton problème vient du profil
de la deuxième procédure, qui fait que tous les appels sont ambigus (on
aurait d'ailleurs le même problème sans faire intervenir les types
étiquetés, simplement avec deux procédures dans le même paquetage qui ne
diffèrent que par un paramètre avec valeur par défaut).

Donc, ou tu te contentes de redéfinir la procédure héritée (en ne
faisant rien du deuxième paramètre), ou tu évites d'appeler la seconde
procédure "Put".
--
J-P. Rosen
Adalog
2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX
Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00
http://www.adalog.fr
Blady
2018-06-24 20:32:22 UTC
Permalink
Post by J-P. Rosen
On ne peut pas, ni en Ada ni en aucun autre langage (au moins ceux
compilés) "déshériter" un type, et c'est heureux, sinon où irait-on en
cas de liaison dynamique?
Autrement dit, si ton type D hérite visiblement de T, tu es tenu par le
contrat de T, et donc par sa procédure Put. Ton problème vient du profil
de la deuxième procédure, qui fait que tous les appels sont ambigus (on
aurait d'ailleurs le même problème sans faire intervenir les types
étiquetés, simplement avec deux procédures dans le même paquetage qui ne
diffèrent que par un paramètre avec valeur par défaut).
Donc, ou tu te contentes de redéfinir la procédure héritée (en ne
faisant rien du deuxième paramètre), ou tu évites d'appeler la seconde
procédure "Put".
Merci Jean-Pierre pour la réponse,

Je m'en doutais un peu. GNAT GPL 2017 me faisait espérer...
Par contre, si je remplace l'appel par "I.Put (4, 3);" le compilateur
génère le programme (pas d’ambiguïté) et exécute la procédure Put privée
(overriding ...).
Je ne comprends pas comment le client puisse exécuter une procédure
déclarée dans la partie privée.

La mettre dans la partie privée n'a donc pas d'effet pour un type hérité ?
(dans le cas d'un type objet simple la procédure déclarée dans la partie
est bien "invisible" du client)

Merci, Pascal.
J-P. Rosen
2018-06-25 12:58:52 UTC
Permalink
Post by Blady
Par contre, si je remplace l'appel par "I.Put (4, 3);" le compilateur
génère le programme (pas d’ambiguïté) et exécute la procédure Put privée
(overriding ...).
Je ne comprends pas comment le client puisse exécuter une procédure
déclarée dans la partie privée.
C'est une question de contrat. Comme la procédure est visiblement une
opération primitive d'un ancètre, on sait que cette procédure existe
(précisément parce qu'il n'y a pas de déshéritage). Ce qui est privé,
c'est qu'elle a été redéfinie - en gros la spec est visible, on cache
qu'on a redéfini l'implémentation. Ce n'est pas forcément passionnant,
mais c'est une autre histoire... En revanche, si l'on ajoutait de
nouvelles opérations primitives en partie privée, elles ne seraient pas
visibles.
Post by Blady
La mettre dans la partie privée n'a donc pas d'effet pour un type hérité ?
(dans le cas d'un type objet simple la procédure déclarée dans la partie
est bien "invisible" du client)
Là on parle de liaison dynamique, c'est toute la différence... En
quelque sorte, la résolution des surcharges a lieu à l'exécution, en
fonction du type réel (aka spécifique) de la donnée.
--
J-P. Rosen
Adalog
2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX
Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00
http://www.adalog.fr
Blady
2018-06-25 19:56:00 UTC
Permalink
Post by J-P. Rosen
Post by Blady
Par contre, si je remplace l'appel par "I.Put (4, 3);" le compilateur
génère le programme (pas d’ambiguïté) et exécute la procédure Put privée
(overriding ...).
Je ne comprends pas comment le client puisse exécuter une procédure
déclarée dans la partie privée.
C'est une question de contrat. Comme la procédure est visiblement une
opération primitive d'un ancètre, on sait que cette procédure existe
(précisément parce qu'il n'y a pas de déshéritage). Ce qui est privé,
c'est qu'elle a été redéfinie - en gros la spec est visible, on cache
qu'on a redéfini l'implémentation. Ce n'est pas forcément passionnant,
mais c'est une autre histoire... En revanche, si l'on ajoutait de
nouvelles opérations primitives en partie privée, elles ne seraient pas
visibles.
Post by Blady
La mettre dans la partie privée n'a donc pas d'effet pour un type hérité ?
(dans le cas d'un type objet simple la procédure déclarée dans la partie
est bien "invisible" du client)
Là on parle de liaison dynamique, c'est toute la différence... En
quelque sorte, la résolution des surcharges a lieu à l'exécution, en
fonction du type réel (aka spécifique) de la donnée.
Merci encore une fois, c'est plus compréhensible pour moi maintenant,
Pascal.

Continuer la lecture sur narkive:
Loading...