Héritage non conforme

24 views
Skip to first unread message

Jocelyn Batton

unread,
Jul 11, 2012, 5:13:03 AM7/11/12
to Groupe des Eiffelistes Francophones
Pardon, j'enchaîne beaucoup les questions en ce moment :$...

Je viens de voir un post sur "non conforming inheritance" du user
group anglais.
J'avais commencé à lire quelque chose sur le sujet ici :
http://www.loria.fr/~colnet/publis/lmo-2006.pdf
J'avais un avis assez partagé sur cette deuxième forme d'héritage
telle qu'elle est décrite dans le sens où cela crée deux notions
d'héritage. De ce fait, cela allait un peu à l'encontre des préceptes
de BM (toujours dans sa bible) d'avoir des concepts peu nombreux mais
très puissants. Je vois également un argument je pense ayant plus de
poids, à savoir que l'on axe plus dans un sens la vision de classe qui
est à l'origine la fusion d'un module et d'un type. Il me semble, si
j'ai bien saisi ce mécanisme, que l'héritage non conforme est un
héritage de module vu que l'affectation polymorphe n'est pas autorisée
et que l'on a recours à cette pratique par soucis de récupérer des
routines qui nous intéressent.

Ma crainte est alors simple : cela ne va-t-il pas engendrer ou tout du
moins encourager la conception des logiciels avec la vision de la
classe comme un module (ce qui à mon sens est déjà le cas actuellement
dans pas mal de langages de programmation) en passant à coté de la
notion de type ?

Un autre point : un des intérêts que je verrais à cet héritage non
conforme serait le "mariage d'intérêt", exemple trouvé (encore et
toujours dans la bible de BM...:)) avec la classe STACK_ARRAY héritant
de STACK et de...ARRAY.
STACK pour l'abstraction que représente la pile et ARRAY pour son
implémentation. Il pourrait alors me sembler justifier que
l'affectation polymorphe ne soit pas autorisée à partir d'une
référence de type ARRAY pour une entité de type STACK_ARRAY car ARRAY
n'a de sens qu'en interne.

J'aimerais avoir votre avis sur ces différents points qui
m'intéressent énormément.

Merci d'avance ! :)

Jocelyn Batton


David Le Bansais

unread,
Jul 11, 2012, 1:05:22 PM7/11/12
to groupe_eiffelis...@googlegroups.com
Perso j'utilise ce mécanisme essentiellement pour éviter la duplication de code, quand les features héritées ne méritent pas une abstraction en soit. 


> Ma crainte est alors simple : cela ne va-t-il pas engendrer ou tout du
>  moins encourager la conception des logiciels avec la vision de la
>  classe comme un module (ce qui à mon sens est déjà le cas actuellement
>  dans pas mal de langages de programmation) en passant à coté de la
>  notion de type ? 

Je ne vois pas trop où est le problème. Au contraire, si le code était simplement copié / collé cela renforcerait l'isolement de la classe.
En évitant d'imposer un type parent conforme, le mécanisme aide aussi à cacher les détails internes d'une implémentation.

David Le Bansais

Jocelyn Batton

unread,
Jul 11, 2012, 5:08:44 PM7/11/12
to Groupe des Eiffelistes Francophones
> Perso j'utilise ce mécanisme essentiellement pour éviter la duplication de
> code, quand les features héritées ne méritent pas une abstraction en soit.

Pourrais-tu me donner un exemple type ?

> > Ma crainte est alors simple : cela ne va-t-il pas engendrer ou tout du
> >  moins encourager la conception des logiciels avec la vision de la
> >  classe comme un module (ce qui à mon sens est déjà le cas actuellement
> >  dans pas mal de langages de programmation) en passant à coté de la
> >  notion de type ?

> Je ne vois pas trop où est le problème.

Le "problème" vient du fait que le mécanisme d'héritage à la base qui
permet :

- de faire des extensions de modules (une classe est un module)
- du sous-typage (la classe est un type ou un module de type dans le
cas générique)

et que l'héritage non conforme est un mécanisme ne prenant en compte
que le premier aspect (encore une fois si je comprends bien ce qu'est
l'héritage non conforme). Mais c'est comme tout, dans l'exemple que je
donne, STACK_ARRAY, je pense que cela peut être une bonne chose mais
ouvre la voix éventuellement à la vision fermée de "classe = module"
en occultant la vision "classe = type". D'où ma question sur le
caractère dangereux de ce mécanisme.

>Au contraire, si le code était
> simplement copié / collé cela renforcerait l'isolement de la classe.

Cela renforcerait l'isolement de la classe ? Pourrais-tu développer ?

> En évitant d'imposer un type parent conforme, le mécanisme aide aussi à
> cacher les détails internes d'une implémentation.

Donc mon exemple de STACK_ARRAY est-il pertinent selon toi ?

Merci d'avance :)

Jocelyn Batton

Victorien Elvinger

unread,
Dec 27, 2012, 7:59:03 AM12/27/12
to groupe_eiffelis...@googlegroups.com
Je me permet de faire remonter le sujet :)


La première fois que j'ai rencontré ce type d'héritage je l'ai intuitivement interprété comme la combinaison de deux mécanisme :
- L'héritage
- L'exportation sélective

Je pensais que le mécanisme permettait l'exportation sélective du lien d'héritage et donc du polymorphisme.
Ainsi un héritage non conforme est un héritage dont le lien de polymorphisme est exporté à aucunes classes (excepté NONE).

Y inherit X

a: X; b: Y

L'affectation polymorphe a := b est permise uniquement dans la classe NONE.


Mais à l'état actuel le mécanisme à une sémantique beaucoup plus large, ce qui est à mon avis un tort.
En effet l'héritage non conforme est aussi un héritage "expansé". Chaque routines sont copiées. Ainsi les routines de l'héritier Y ne sont pas les mêmes que celles du parent X.
Cette copie génère des confusions, notamment lors de l'appel d'une routine à exécution unique. Si la routine est exécuté sur un objet de type X elle peut être exécutée de nouveau sur un objet de type Y.
Ainsi une constante n'aura pas la même référence dans X que dans Y.

L'héritage non conforme exporte également toutes les caractéristiques à la classe NONE. Ce dernier aspect du mécanisme reste discutable.
Il suffit juste de se demander la signification sémantique du mot "inherit". Est-ce l'expression d'un lien polymorphique uniquement (je pencherais pour cette interprétation) ou d'un lien polymorphique mais aussi de la représentation de l'ensemble des caractéristiques de la classe.


Je suis d'accord avec toi il y a eu une "fragmentation" de l'héritage avec l'apparition de l'héritage non conforme.
La suppression de l'aspect copie serait selon moi une bonne chose, elle ôterait des ambiguïtés et ouvrerait la possibilité d'un support complet de l'exportation sélective pour l'héritage.
Ce support n'a peut-être pas d'utilité immédiat mais il a le mérite d'unifier l’héritage conforme et non conforme et d'élargir le champ d'utilisation de l'exportation sélective (cette dernière pourrait également être étendue à la conversion). On retrouve une certaine simplicité.


Concernant ton inquiétude sur les modules :
Je ne pense pas que la vision d'une classe comme un module soit un réel problème.
L'héritage de service ou d’implémentation est une bonne illustration de la nécessité de cet aspect de module.
Si tu souhaite utiliser des fonctions mathématiques ou des constantes particulières (ex : constantes HTML) tu hérite d'une classe.
Désormais, au lieu de créer un lien polymorphique qui n'a pas de réel sens, tu peux utiliser l'héritage non conforme.
Tu as également plus de souplesse. Tu peu modifier les signatures de tes caractéristiques sans inquiétudes de rétro-compatibilité ...


Victorien ELVINGER

Jocelyn Fiat

unread,
Jan 8, 2013, 3:53:31 AM1/8/13
to groupe_eiffelis...@googlegroups.com
Petite remarque rapide sur le theme.
En fait je crois qu'a l'origine l'heritage non conforme etait plutot destiné à heriter d'une implementation sans etre conforme .. (la je repete un peu le nom "non conforming inheritance") ...
prenons le cas de ARRAYED_LIST [G] ... (sauf erreur de ma part) la semantique est une LIST ... implementée grace a ARRAY ... et pas du tout une liste qui soit aussi un array

Dans le passé cela heritait de ARRAY [G] et LIST [G]  , mais le "hic" c'etait que dans certain code, la conformance a ARRAY etait utilisée ce qui etait clairement dangereux.
Pour remedier a ce type de mauvais usage, il existe des solutions ... supprimer l'heritage a ARRAY et utiliser par clientelisme , mais ce n'est clairement pas super en terme de reutilisation de code etc ...

Et je pense que la notion de "non conforming inheritance" vient de ce besoin .. en gros, on heriterait de ARRAY de facon non conforme .. ce qui permet de reutiliser son implementation, et redefinir ce qui doit l'etre, mais tout en empêchant quiconque de faire   mon_array := mon_arrayed_list ... et utilise mon_array en tant que ARRAY ...

Partant de ce besoin, comment rajouter cette notion a Eiffel, sans rajouter un nouveau mot clef etc ... a l'epoque il me semble qu'a la suite de discussion le choix s'etait porté sur  "inherit {NONE}" ... peut etre en imaginant que par la suite on puisse avoir ce que Victorien appelle une exportation selective ... mais l'idee etait vraiment d'exprimer l'heritage NON conforme ... le choix aurait put etre  "include" "import" ... "expand" ... ou je ne sais quoi d'autre.

Maintenant il est vrai qu'il est deroutant d'avoir des references constantes qui ne soit pas le meme  ... typiquement ... les onces   (sachant que   foo: STRING = "abc"   est en fait une once cachée)
mais la semantique des onces va a l'encontre de l'heritage non conforme.
En regle general il faut etre prudent avec les onces. Et bien se rappeler aussi que   {FOO [INTEGER]}.my_once: STRING et    {FOO [STRING]}.my_once: STRING n'auront egalement pas la meme reference avec my_once declarée dans FOO. Autre cas qui peut surprendre, quand on passe de single thread a multithread ,ne pas oublier que par defaut les onces sont par thread et non pas process .. mais bon la je m'ecarte du sujet.

Bref, tout ca pour donner ma vision de la chose (qui n'engage que moi) ... l’héritage non conforme est pour moi principalement une solution pour réutiliser une implementation, sans garder la conformance (peut importe NONE etc ...). Et il faut être prudent avec les onces.


-- Jocelyn (Fiat)

Victorien Elvinger

unread,
Jan 18, 2013, 12:31:33 PM1/18/13
to groupe_eiffelis...@googlegroups.com
 la semantique des onces va a l'encontre de l'heritage non conforme.

Je dois mal cerné leur sémantique. Je ne comprends pas d'où peut venir cette incompatibilité.

 
il faut être prudent avec les onces. Et bien se rappeler aussi que   {FOO [INTEGER]}.my_once: STRING et    {FOO [STRING]}.my_once: STRING n'auront egalement pas la meme reference avec my_once declarée dans FOO. Autre cas qui peut surprendre, quand on passe de single thread a multithread ,ne pas oublier que par defaut les onces sont par thread et non pas process


C'est vrai que les routines à exécution unique par classe apporte parfois des problèmes.
Généricité
Je n'étais pas au courant de cette aspect sémantique de once.
A moins que la routine soit une requête dont le résultat est d'un type générique, je trouve cette aspect assez curieux.

Thread - Multi-thread
le fait qu'une requêtes à exécution unique donnait un résultat d'un type non expansé s’exécute dans chaque thread n'est pas choquant en soi. En effet, n'étant pas de type séparé l'objet créé ne peut être que dans le thread courant.

D’ailleurs pour les requêtes à exécution unique multi-thread donnait un résultat d'un type non expansé et non séparé il y a un problème.
En effet dans  quel thread est l'objet ? Son accès n'est pas verrouillé (puisqu'il n'est pas séparé) ...


A se demander si once ne devrait pas être revue ...
L plupart du temps ont rencontre des requêtes à exécution unique.
Souvent elles peuvent être substituées par une routine à exécution unique par objets (once {OBJECT}) qui règle de nombreux problèmes.
Mais dans cette substitution ont perd en efficacité (mémoire et temps).

Reply all
Reply to author
Forward
0 new messages