Mais à la limite, on s'en fout...Si, la cohérence du type réellement utiliséCe serait extrêmement vicieux. J'ai un A, j'appelle carre dessus, la postcondition sur le résultat me garantit qu'il est >= 0. La précondition sur A::f me dit que j'ai besoin que mon entier soit >= 0, ça tombe bien, c'est ce que carre me garantit !
Si j'autorise B à restreindre les préconditions de A, mon programme va planter lamentablement, car je n'ai plus rien de tangible auquel me fier. J'ai perdu tout le bénéfice de mon contrat.
Mais je ne connais pas le type réellement utilisé. Le gros bénéfice de la PPC, c'est qu'elle me garantit que ce qui est valable pour un A, l'est pour tout B qui dérive de A.
Tu sais que tu vérifie le contrat, point barre.
Ce que dit le contrat, à l'extrême limite, on s'en fout, on sais juste qu'il est là pour veiller à ce que l'objet reste cohérent.
Si, parce que tu dérive de ton objet de base, les conditions du contrat doivent évoluer, je ne vois absolument pas pourquoi l'empêcher... de toutes manière, tu manipulera ton objet dérivé comme un objet de base: les comportements que tu invoquera à son sujet sont des comportements que tu sais que l'objet de base implémente.
Je dirais même que tu te fout royalement de savoir si le comportement de l'objet dérivé est adapté ou non...
La seule chose qui compte, c'est que si le comportement est adapté et que le contrat nécessite de "addenda" pour permettre au comportement d'avoir lieu, c'est que ce soit le contrat de l'objet dérivé qui prenne le pas sur le contrat de l'objet de base, point-barre, parce qu'un objet dérivé peut être considéré comme étant dans un état cohérent alors que l'objet de base, dans les mêmes circonstances, serait considéré comme étant dans un état incohérent, et vice versa...
Ce qui importe, c'est que, lorsque l'on récupère l'objet réel (avec son type réel), l'objet soit bel et bien dans un état cohérent.
S'il appartient au concepteur de l'objet de base de déterminer le contrat qui assure que l'objet est dans un état cohérent, et qu'il admet le fait que cet objet puisse être dérivé, c'est au concepteur de l'objet dérivé de déterminer le contrat qui assure qu'il est dans un état cohérent.
Et l'utilisateur final n'a qu'à s'inquiéter de savoir s'il souhaite la vérification ou non du contrat, en sachant que, s'il la demande pour l'objet dérivé, il aura la certitude qu'il respecte les normes édictées pour cet objet particulier, ET que, s'il la demande pour l'objet de base (un objet réellement de base, et non un objet "qui se fait passer pour" un objet de base), ce seront les normes édictées pour cet objet de base qui seront prises en compte...
Je ne vois absolument pas ce qui est choquant là dedans...
Mais en tant qu'utilisateur de l'objet, tu n'en a de toutes façons pas besoin...Lorsque j'ai écrit main, je me suis basé sur ce que je connaissais. Le contrat de A::f. Je n'ai pas connaissance du contrat des classes dérivées. Je ne peux pas, leur ensemble est virtuellement infini. En supposant que je n'ai aucune règle sur le contrat dans les classes dérivées, je ne sais plus rien. J'ai un contrat, mais il ne me sert à rien, car je ne peux plus me baser dessus.Je sais que, bien que d'un point de vue purement géométrique, un carré est un rectangle "particulier", il ne faut pas permettre à carré d'hériter de rectangle parce que cela ne correspond à rien de parler de "longueur" et de "largeur" sur un carré.
Par contre, un carré peut parfaitement hériter de losange (si on utilise comme donnée les quatre coins, et qu'il n'y a pas de données sur la taille des diagonales)
Ce n'est pas à l'utilisateur de l'objet de décider du contrat, c'est à son concepteur, dés lors, si même tu viens à avoir 150 classes qui dérivent de ta classe de base, tu peux avoir entre 0 et 150 adaptation du contrat, c'est au concepteur de voir si elles sont nécessaires et opportunes
En tant qu'utilisateur, tu sais que, quel que soit le type réel que tu aura choisi pour ta variable, si tu utilise le mode débug, tu aura une erreur si les conditions particulières du contrat ne sont pas respectées
Honnêtement, je ne vois pas ce qui peut te chagriner là dedans.
Mais, pour autant que la vérification reste cohérente avec le type réel (que le contrat du type B soit cohérent avec le type B), tu garde exactement les même gardes fous... et ce n'est, je le redis encore, pas à l'utilisateur de s'en inquiéter, mais à celui qui crée les types en question...Ces règles sont là comme des garde-fous. Grâce à ces règles, je sais que je n'ai pas le droit d'écrire le B::f que j'ai écrit, et donc, que j'ai la garantie que ma fonction, qui fonctionne pour un A, fonctionnera pour tout B ou C qui dérive de A, sans que je doive modifier ma fonction appelante.
Cela reste tout à fait transparent pour l'utilisateur, et c'est bien ce qu'il faut.
L'utilisateur sais qu'un contrat permet d'assurer la cohérence des données s'il passe en mode débug, et il sait que le concepteur du type aura pris ses précautions pour que, si le contrat nécessite une adaptation au type réel, ce soit cette adaptation qui sera prise en compte...
J'ai l'impression qu'il y a effectivement un problème de communication...Je crois qu'on a un problème de communication . J'ai l'impression que ce que tu défends, c'est que "on peut s'en sortir sans" et "c'est trop restrictif". Mon point de vue à moi, c'est que les garanties qu'on gagne, valent largement les restrictions qu'on s'impose.
Moi, ce que je défend, c'est le fait que chaque type doit être responsable des propres contrats qu'il doit appliquer, ce qui n'empêche absolument pas d'avoir un type dérivé qui utilise (tout ou partie) du "contrat type" de son type de base, en sachant que, si une adaptation de ce "contrat type" est nécessaire, cette adaptation doit être prise en compte lors de la vérification
[EDIT]De manière beaucoup plus simplement exprimée: si tu adaptes un type, tu adaptes peut-être aussi les conditions dans lesquelles ce type est utilisé.
Tu n'est pas obligé d'adapter les conditions d'utilisation, mais si tu le fait, il est normal que ce soit ces conditions adaptées qui servent de garde fou
Partager