Alors, il est peut être juste que je pars sur de mauvaise hypothèses, mais alors, dites moi quelles hypothèses je dois utiliser et en quoi les miennes sont mauvaises...
Pars des hypothèses suivantes :
- la précondition doit être vérifiable par l'appelant (ie, l'appelant doit être en mesure de vérifier qu'il respecte sa part du contrat)
- le test du contrat dans l'appelé est totalement facultatif, il n'est là théoriquement qu'en phase de debug
Je pense que si tu fournis une méthode virtuelle de vérification à appeler pour savoir si tu as le droit d'appeler la fonction, tu déformes complètement l'idée de départ. Parce que dans ce cas, ce que tu fais, c'est imposer à l'appelant la structure suivante :
Et finalement, si tu le faisait dans ta classe, plutôt que de l'imposer à l'appelant, ça donnerait :
function safe_f() pre Nothing
safe_f() n'a pas de préconditions, et du coup, tu n'as pas "restreint" les préconditions d'appel...
Pour aller encore plus loin, suppose que j'ai les fonctions suivantes :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class A {
int carre(int x) pre Nothing, post ret >= 0 { return x * x; }
virtual int f(int x) pre x >= 0, post ret >= 0 { return (int) sqrt(x); }
};
class B {
virtual int f(int x) pre x >= 2, post ret >=0 { return (int) sqrt(x-2); }
}
int main()
{
A* a1 = new A();
A* a2 = new B();
a1->f(a1->carre(1)); // super !
a2->f(a2->carre(1)); // aïe !
} |
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.
Partager