L'infrastructure .NET s'est approprié la primeur de l'aspect multi-langage.
Cet argument relève-t-il d'une campagne marketing ou d'un réel besoin technique
?
De sérieux éléments de réponse ont déjà été proposés
dans l'article
précédent de Sami Jaber.
Mais si l'on y réfléchit bien, disposer de plusieurs langages pouvant cohabiter dans le même environnement d'exécution n'est pas nouveau ; de nombreux langages de programmation disposent de compilateurs qui produisent du Bytecode Java, et peuvent donc tout à fait être employés pour bâtir des applications 100% Java fonctionnant sur n'importe quelle JVM compatible.
Cet article se propose de vous présenter quelques langages novateurs compatibles avec la machine virtuelle Java. Plus qu'une nouvelle syntaxe, c'est un nouvel horizon qu'apporte chaque langage de programmation : des concepts, des patterns, une idéologie.
Les langages que nous allons présenter reposent sur l'une des techniques suivantes :
Java a été conçu voici une dizaine d'années. L'objectif à l'époque était de disposer d'un langage Orienté Objet, portable, doté d'une syntaxe proche des langages connus (C, C++) et relativement simple à prendre en main. Je pense, sans trop craindre de faire se lever les foules, que ces objectifs ont été atteints.
Toutefois, Java se voulant simple à appréhender, il prive les développeurs expérimentés de certains aspects syntaxiques et conceptuels ainsi que de certains outils indispensables à l'obtention d'excellentes performances. De plus, les recherches (et les trouvailles) concernant les langages de programmation ne se sont pas arrêtées le jour de la naissance de Java. Au contraire, notre réflexion est plus fine aujourd'hui, notre habitude des langages Orientés Objets plus grande, ce qui nous permet de voir plus loin.
Mais qu'à cela ne tienne : si le langage Java ne vous donne pas entière satisfaction, ne vous détournez pas pour autant de sa plate-forme (J2EE, J2SE ou J2ME) ni de son environnement d'exécution (JVM) : laissez-vous tenter par l'un des langages qui suit.
Parmi les trois familles de langages que nous allons vous présenter, nous mettrons tout de même l'accent sur ceux qui s'approchent de la philosophie de Java tout en étendant ses possibilités.
Pour les afficionados du langage Eiffel de Bertrand Meyer (père de la conception par contrats), voici deux compilateurs Eiffel qui produisent directement du Bytecode. Malheureusement, le langage Eiffel est relativement peu utilisé, d'où la faible audience de J-Eiffel auprès de la communauté des développeurs (Java ou Eiffel d'ailleurs). Si vous souhaitez savoir comment développer des applets Java en langage Eiffel, cela vaut tout de même le détour.
Conceptuellement, Eiffel est tout de même très novateur comparé à Java puisqu'il apporte la rigueur de la conception par contrats. Pour simplifier, disons que le langage permet de décrire des
Ne vous détournez pas du sujet, même si Eiffel n'évoque rien pour vous : les prochaines sections reviendront sur la programmation par contrat et son intégration avec la syntaxe du langage Java ! Il n'est plus besoin d'apprendre Eiffel pour programmer par contrat.
Talks2 est un environnement de développement Smalltalk complet qui fonctionne dans une JVM. Les connaisseurs y retrouveront le Browser de Classes, le Workspace, Transcript.... Talks2 traduit du Smalltalk en Java et peut donc s'utiliser pour tirer parti de la plateforme J2EE !
Le dynamisme du langage (et de son typage) était très populaire auprès de ses utilisateurs. La contrepartie bien entendu de petits soucis de robustesse (certains problèmes ne sont détectés qu'au cours de l'exécution) et de performances.
Le système JGNAT offre un environnement de développement Ada 95 complet pour la plate-forme Java. Cela comprend, entre autres, un compilateur produisant du Bytecode (compatible Java 1.1 et supérieurs).
Ada 95 est tout l'inverse de SmallTalk : un langage très robuste, très contraignant, qui permet de détecter énormément de problèmes lors de la compilation. L'utilisation de PRAGMAS donne accès à de nombreuses fonctionnalités techniques sans polluer le code Ada (c'est un début d'Aspect Programming, cf sections suivantes).
Enfin un langage qui rend Java embarquable dans la fusée Ariane ?
Jython est une implémentation en langage Java du célèbre langage de script Orienté Objet Python. Très dynamique, doté d'un typage dynamique (comme Smalltalk), Python est assez populaire dans le monde du prototypage, ainsi que du calcul scientifique.
Il est un autre domaine où Python, et en particulier Jython, est intéressant : lorsque l'on souhaite donner aux utilisateurs d'un logiciel complexe la possibilité de développer des macros, des scripts pour automatiser certaines actions répétitives. On retrouve cette pratique dans les suites bureautiques (Microsoft Office permet de développer les macros en VisualBasicScript) ainsi que dans de nombreux logiciels exposant un modèle Objet.
Si d'aventure vous développez un logiciel Java complexe et souhaitez permettre à vos utilisateurs de l'étendre par quelques macros, songez donc à embarquer l'interpréteur Jython dans votre application : toute instance de classe Java sera manipulable très simplement par la syntaxe Python !
iContract, comme son nom l'indique, est un outil permettant aux développeurs Java de tirer parti de la conception par contrat, sans pour autant avoir à changer de langage de programmation.
iContract est un pré-compilateur qui met à contribution des commentaires spéciaux (à la mode des commentaires JavaDoc) pour décrire pré-conditions, post-conditions et invariants. La pré-compilation produit du code 100% Java (ou, pour vous simplifier la tâche, du Bytecode directement), que vous pouvez exécuter dans n'importe quelle Machine Virtuelle Java. Les contraintes, elles, sont exprimées dans un sous-ensemble du langage OCL (Object Constraint Language).
Bien entendu, le pré-compilateur iContract vérifie, autant que faire se peut, que votre code Java respecte les contrats fixés. Par exemple, il est impossible d'invoquer successivement deux méthodes dont les post-conditions de la première ne sont pas compatibles avec les pré-conditions de la seconde.
Cela s'inscrit évidemment dans un contexte Orienté Objet, et donc la relation d'héritage revêt une sémantique d'autant plus puissante : chaque méthode d'une sous-classe se doit de respecter le contrat de la méthode qu'elle redéfinit (le cas échéant).
Enfin, on trouve un gadget dans l'outil qui permet de ne vérifier les contrats que partiellement. Par exemple, vous pouvez demander au pré-compilateur de ne vérifier que les pré-conditions ; cela peut même être précisé classe par classe.
Mais cessons de vous faire saliver : voici un exemple de syntaxe Java augmentée des commentaires spéciaux de iContract :
package iContract.doc.tutorial.Person;
public interface Person {
/** * @post return > 0 // age always positive */
public int getAge();
/** * @pre age > 0 // age always positive */
public void setAge(int age);
}
package iContract.doc.tutorial.Person;
public class Main {
/** Test driver method. * Create an employee and print its age. */
public static void main( String argv[] ) {
Employee employee = new Employee( 25 );
System.out.println( "Employee's age is: " + employee.getAge() );
employee.setAge( -1 ); // this will break!} } java iContract.doc.tutorial.Person.Main Employee's age is: 25 java.lang.RuntimeException: Employee.j:22: error: precondition violated (iContract.doc.tutorial.Person.Employee::setAge(int)): (/*iContract.doc.tutorial.Person.Person::setAge(int)*/ (age > 0)) at iContract.doc.tutorial.Person.Employee.setAge(Employee.java:124) at iContract.doc.tutorial.Person.Main.main(Main.java:14)
AspectJ est l'implémentation Java de cette nouvelle tendance que constitue l'Aspect Programming. Ce courant de pensée part de la constatation que, dans le code source (Java ou autre) de nos logiciels, on retrouve certains "aspects" du code disséminés dans plusieurs (parfois de nombreuses) classes. Un exemple fréquemment cité est celui de la gestion des traces (journalisation), dont le code apparaît effectivement à chaque endroit où une trace est imprimée dans le fichier ou la base de données constituant notre journal.
La question est la suivante : comment réunir ces bouts de code traitant de la même problématique mais répartis à travers toute l'application ? Eh bien il faut dépasser les contraintes fixées par la programmation Orientée Objet et inventer un nouveau concept : la Programmation Orientée Aspects (AOP en anglais). Rassurez-vous, les deux styles de programmation sont complémentaires, et non pas (du tout) antithétiques.
L'AOP nous invite donc à décrire le code récurrent (mais a priori disséminé) dans un Aspect (écrit lui-même dans un langage qui peut être proche de Java, c'est le cas avec AspectJ), puis à appliquer l'Aspect à des endroits très précis de notre logiciel. Ce dernier se concentre donc sur des problématique fonctionnelle cohérente, laissant le soin aux Aspects de gérer les problématiques transversales aux classes de l'application (et souvent techniques).
Un petit exemple pour éclaircir ce discours brumeux ? Allons-y : la classe "Point" aurait besoin de gérer un certain nombre d'assertions (vérification de préconditions). Nous considérons ici que ceci ne relève pas de ses responsabilités, mais plutôt de celles d'un Aspect ; le code des préconditions est donc externalisé, et géré par l'aspect "PointAssertions" (et uniquement par lui).
class Point {
int x, y;
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
public static void main(String[] args) {
Point p = new Point();
p.setX(3);
p.setY(333);
}
}
aspect PointAssertions {
private boolean Point.assertX(int x) {
return (x <= 100 && x >= 0);
}
private boolean Point.assertY(int y) {
return (y <= 100 && y >= 0);
}
before(Point p, int x): target(p) && args(x) && call(void setX(int)) {
if (!p.assertX(x)) {
System.out.println("Illegal value for x");
return;
}
}
before(Point p, int y): target(p) && args(y) && call(void setY(int)) {
if (!p.assertY(y)) {
System.out.println("Illegal value for y");
return;
}
}
}
Vous notez que l'aspect "PointAssertions" déclare, pour plus de lisibilité, deux méthodes privées (en syntaxe Java), et applique ensuite ces méthodes vérifiant des contraintes sur X et Y aux méthodes de la classe Point "setX()" et "setY()".
Nous pourrions dès lors ajouter d'autres comportements à la classe Point, sans avoir à modifier son code (ce qui est naturel, puisque sa logique n'évolue pas, elle). Quelques exemples :
JavaLayers est une implémentation de la notion de Mixin Layers en Java. Il existe plusieurs manières d'exprimer cette idée ; nous allons tenter d'en synthétiser deux.
La première consiste à dire que la relation d'héritage entre deux classes crée une dépendance forte entre la classe fille et sa mère. Or, dans certains cas, il serait intéressant de pouvoir faire hériter une classe fille (qui enrichit le patrimoine de sa mère d'un comportement générique) d'une mère dont on décide de l'identité plus tard.
Il suffit donc de dire que la classe fille va hériter d'une classe... qui est un type paramétrique. C'est-à-dire un template. Or Java ne propose pas ce mécanisme : les types Java ne peuvent pas être paramétrés (c'est d'ailleurs la raison pour laquelle nous passons notre temps à transtyper les objets stockés dans les collections génériques Java). JavaLayers est donc un pré-compilateur qui permet, à partir d'un sur-ensemble du langage Java, de décrire des types paramétriques et de générer des classes Java lors de l'instanciation de ces types.
La seconde manière de décrire la notion de Mixin layer est plus conceptuelle : elle revient à dire que les classes sont capables de décrire des comportements génériques réutilisables (traces, comportements techniques divers). Mais les techniques Orientées Objet (Design Patterns) ainsi que la programmation Orientée Aspect peinent à décrire des collaborations réutilisables entre classes. Ce qui est précisément la spécialité des MixinLayers : ce sont des couches (des ensembles) de classes dont les relations sont fixées, mais dont l'identité des classe ne l'est pas. Il suffira donc d'instancier les MixinLayers en choisissant les classes qui souhaitent tirer parti de collaborations prédéfinies.
Je vous invite à creuser le sujet en lisant les thèses de Don Batory et Yannis Smarragdakis sur les Mixin Layers (en C++) et la documentation de JavaLayers.
Nous n'avons pas évoqué dans cet article les langages plus exotiques tels que :
Sachez simplement que de nombreux projets, dans le contexte de l'entreprise ou de thèses universitaires, voient le jour assez souvent. La plupart de ces nouveaux langages sont Open Source, ou du moins gratuits.
Il existe de nombreux langages de programmation sur le marché. Ils diffèrent par leur syntaxe, plus ou moins bavarde, et par leur philosophie.
Nous avons vu dans cet article qu'il était tout à fait possible de concilier le langage, l'environnement d'exécution et la plate-forme Java avec ces autres langages de programmation (que ce soit par la syntaxe ou par le runtime).
Le multi-langage n'est donc pas l'apanage de la plate-forme .NET même s'il est moins mis en avant. Nous espérons que cet article vous aura convaincu, ainsi que du fait que les langages de programmation ne se caractérisent pas uniquement par leur syntaxe.
Auteur : Thomas GIL
Copyright © DotNetGuru
Ressources :
JGNAT : ftp://cs.nyu.edu/pub/gnat/jgnat/
iContract : http://www.reliable-systems.com/tools/iContract/iContract.htm
AspectJ : http://aspectj.org
JavaLayers : http://www.cs.utexas.edu/users/richcar/JavaLayers.html
La liste des langages destiné à la JVM : http://grunge.cs.tu-berlin.de/~tolk/vmlanguages.html