C'est malheureusement une critique qui revient souvent. D'une part, oui, on connait JML, mais cela ne correspondait pas à nos besoins, donc on a choisi de partir de Modern Jass. Il y a une bonne dizaine de frameworks de programmation par contrats en Java (voyez ma réponse sur Hacker News[0]), et on en a choisi un en particulier parce qu'il fallait bien faire un choix, et que c'était celui qui nous convenait le mieux.
Quant aux différences JML vs Cofoja, du point de vue de l'utilisateur, j'ai répondu à la même question sur r/programming[1], il y a une semaine et je vais résumer ici : JML est plus complet, plus gros, fait beaucoup plus que des contrats, utilise sa propre toolchain, et a tendance à traîner le pied au niveau du support de nouvelles constructions dans le langage Java (du fait de la richesse des fonctionnalités qu'ils proposent, ajouter n'importe quelle construction au langage nécessite d'étendre le modèle conceptuel des spécifications JML de manière cohérente, ce qui n'est pas évident[2]).
Le principal problème qui a fait que l'on a éliminé JML de nos options assez tôt est qu'il utilise sa propre toolchain, dont la version stable ne supporte pas Java 6, et ce n'était absolument pas envisageable de faire migrer des portions entières de code Google sous une boucle de compilation différente. Au-delà du défi technique que cela représente, ce serait beaucoup trop risqué en termes d'ingénierie et un tel projet n'aurait jamais vu le jour à Google. Cofoja, et son prédecesseur Modern Jass, s'intègrent aux outils standards de Java, via des APIs standards; la syntaxe n'est peut-être pas idéale (les chaînes de caractères dans les annotations) mais le framework est utilisable « immédiatement » de manière très peu intrusive dans n'importe quel projet Java (et même GWT en mode Java).
Liens (en anglais) :
[0] http://news.ycombinator.com/item?id=2183504
[1] http://www.reddit.com/r/programming/...r_java/c1flbip
[2]*http://citeseerx.ist.psu.edu/viewdoc...0.1.1.159.6215
Et si en étendant la notion de typage fort, on passait carrément au typage sélectif : une première analyse est effecutée sur les paramètres de la méthode, permettant d'invoquer la fonction, enfin l'implémentation, qui convient.
Une fonction a plusieurs implémentations, avec la même signature, mais chacune d'elles seront invoqués-ou refusées- sélectivement après l'analyse des paramètres.
Exemple :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 interface MonExemple{ MaMethode( int i); } class MaClass implements MonExemple{ @Choix( i=0) MaMethode( int i){...} @Choix( i>0) MaMethode( int i){ ...} @Choix( i<0) MaMethode( int i){ ...} }
Les contrats au sein même des interfaces, c'est supremement sympa pour être certain que toutes les implémentations de ces interfaces respecteront une certaine norme.
Par contre, j'aimerai bien que Java embarque directement les contrats, sans passer par des extensions tierces qui du coup ne disposeront jamais d'aucune aide des environnement de développement au niveau de la complétion ou autre. Le C# a embrassé les contrats dans sa version 4 (encore qu'il faille un plugin additionnel pour les activer dans l'IDE, et non utilisable dans Visual express), à quand Java ? :-)
eclipse et netbeans intégrent automatiquement toutes les annotations qu'il trouvent dans votre classpath de projet. donc vous avez d'office l'autocompletion, la doc etc. Quand au supprot pour la vérification, je suppose que ce genre de règle viens avec soit des test unitaires ad-hoc pour maven ou autre (que les ide peuvent intégrer sans soucis), soit avec des règle de weaving pour les injecter dans le code généré (encore une fois, ceci est géré par les ide). Bref, je ne m'inquiéterait pas donc de ce coté là. Certes vous n'aurez probablement pas de la part de l'IDE quelque chose du style
souligné en rouge avec le commentaire "le contrat dit que ca doit retourner entre 0 et 23, valeur -1 non autorisé dans instruction return"
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 public int getHour(){ return -1; // not implemented }
mais bon![]()
Il me semblait que justement les contrats améliore les possibilités d'analyse statique. Un exemple simple comme celui présenté est faisable. Eclipse detecte bien des trucs du genre
C'est juste qu'il faut le programmer... Pas simple...
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 if(false) { // du code inutile... }
Mais plus une question de ressources et d'argent que de faisabilité.
Je connais cette lib inspirée d'Eiffel qui existe depuis 6 ans au moins.
http://jcontractor.sourceforge.net/
Requires, Ensures... ça ressemble à s'y méprendre aux Code Contracts de .NET 4.0
Si ce n'est qu'ils ont choisi de se baser sur des annotations plutôt que sur des appels de méthode...
Pas de questions techniques par MP ! Le forum est là pour ça...
Tutoriels : Les nouveautés de C# 6 - Accès aux données avec Dapper - Extraction de données de pages web à l'aide de HTML Agility Pack - La sérialisation XML avec .NET (Aller plus loin) - Les markup extensions en WPF
ALGORITHME (n.m.): Méthode complexe de résolution d'un problème simple.
Pas de questions techniques par MP ! Le forum est là pour ça...
Tutoriels : Les nouveautés de C# 6 - Accès aux données avec Dapper - Extraction de données de pages web à l'aide de HTML Agility Pack - La sérialisation XML avec .NET (Aller plus loin) - Les markup extensions en WPF
ALGORITHME (n.m.): Méthode complexe de résolution d'un problème simple.
Pour résumer, quand on écrit une fonction (en Java ou en ??) qui a des paramètres, on a intérêt à se soucier de la validité de ceux-ci, si on veut éviter les bugs.
Dans la programmation par contrat (cf. B Meyer), on établit un contrat entre la fonction et le code client qui appelle la fonction : la fonction peut être écrite en supposant que ses paramètres vérifient une précondition ; en retour, elle garantit son effet par le biais d'une postcondition. Cette notion de contrat est finalement assez naturelle, si on cherche à concevoir proprement.
Par exemple, si on veut écrire une fonction qui interclasse deux tableaux triés, on écrit
- Précondition = les 2 tableaux sont triés
- Postcondition = le tableau résultat est trié et contient exactement tous les éléments des 2 tableaux
Tout le monde bénéficie des avantages de ce contrat : la fonction est plus simple à écrire car elle peut s'appuyer sur l'hypothèse formulée par la précondition ; le code client qui appelle la fonction a la garantie que la fonction a fait son travail correctement.
En Eiffel, préconditions et postconditions sont des formules du calcul des prédicats, sans quantificateur. Ces assertions font partie intégrante de l'interface de la classe.
Pour l'histoire, il faut savoir que Eiffel permet aussi d'écrire d'autres assertions comme les invariants d'itérations et ainsi de réaliser la preuve de l'itération. Pour les programmeurs soucieux d'écrire du code impeccable, c'est un vrai bonheur ....
Pour appliquer ce type de programmation dans un langage dont la définition ne prévoit pas ce mécanisme, comme Java, on peut :
- utiliser JML qui permet d'écrire des pré et post avec quantificateurs, qui fait quelques vérifications pour interdire d'écrire des assertions qui modifient l'état de l'objet, et qui génère du Java.
Malheureusement, JML n'a pas évolué et n'est compatible qu'avec Java 1.4 .... Dommage, c'était bien.
- utiliser assert pour faire de la programmation défensive ; la fonction se défend elle-même contre les mauvais paramètres. Pour prévenir le client qu'une exception peut être déclenchée, on ajoute un commentaire en langage naturel avec la balise @exception.
Pour éviter toute mauvaise surprise, le programmeur est tenu de n'utiliser dans un assert que des fonctions qui observent l'objet, mais qui, surtout, ne le modifient pas, de sorte que si on désactive les assert (option -ea de java), le programme fonctionne de la même façon. Mais, le programmeur fait ce qu'il veut, le compilateur ne vérifie rien ......
Dans un assert, on ne peut pas utiliser de quantificateur ; pour écrire une propriété vraie sur un intervalle on est obligé d'écrire une fonction booléenne qui fait le test.
On utilise rarement assert à la fin de la fonction pour vérifier son bon fonctionnement, mais on pourrait le faire pour vériier la postcondition.
Donc pour résumer, si Java doit intégrer les pré et post, ce sera une bonne chose. S'il pouvait aussi intégrer les invariants d'itérations, on ne verrait peut-être plus trainer du code Java avec 2 itérations imbriquées et un return pour en sortir ......
Il reste à former les programmeurs pour utiliser les assertions et les inciter à bannir le bricolage. Tout un programme ....![]()
Pour moi et d'après plusieurs lectures (sur lesquelles je ne mets plus la main), le but des assert en java est de pouvoir blinder le développement.
On les active en développement et on les désactive en production pour gagner en vitesse. Tout ce qui doit systématiquement être testé même en production (par ex des valeurs saisies par un utilisateur) ne doit pas l'être via un assert(...) mais via un if (...) throw...
En tout cas, c'est comme ça que les utilise. Sinon, je ne vois pas la différence entre des assert et des if.
Partager