Groovy, Ruby avec JRuby. Ces langages ne sont certes pas nouveaux sur la plate-forme Java, mais en 3 ans ils ont énormément évolués et sont désormais courants dans le monde de l’entreprise.
Depuis l'intégration du moteur de JavaScript Rhino dans le JDK 6, une mouvance de langages à typage dynamique est arrivée sur la JVM.
Du fait de l'inadaptation de la JVM, le besoin d'intégrer des notions de typages dynamiques s'est fait sentir. C'est ainsi qu'est né la JSR 292, améliorant le support des langages dynamiques.
Celui-ci, qui est projet OpenJDK, a été créé dans le but de transformer la JVM en une MLVM (Multi Language Virtual Machine). Ce projet regroupe plusieurs sous-projets dont le but est de réduire la difficulté d'intégrer de nouveaux langages pour la JVM.
En complément de la JSR 292, on peut retrouver : - une implémentation des continuations, chères aux langages fonctionnels - l'injection d'interface et de nouvelles méthodes dans une classe, chère aux langages dynamiques tels que Ruby
La liste complète des sous-projets est disponible ici.
Jusqu'à présent, les personnes en charge de l'implémentation de langages typés dynamiquement sur la JVM (entre autre Jython pour le Python et JRuby) ont dû rivaliser d'ingéniosité pour réussir l'intégration sur cette machine virtuelle. En particulier, ils utilisent à outrance le type Object, car ils ne peuvent pas connaître à l'avance le type de chaque objet, ils encapsulent les types de base dans des classes, etc. En "contournant" les restrictions de Java par ces biais, ils perdent les avantages de la JVM et ses capacités à optimiser l'exécution du code, ce qui résulte en de moins bonnes performances. De plus, le bytecode est globalement non-typé, donc il y a toujours un moyen de contourner le typage statique de la JVM, sauf pour un point majeur : l'invocation de méthode. En effet, le bytecode n'impose que deux restrictions sur les types :
De plus, la JVM vérifie le bytecode pour être sûr que les règles précédemment citées sont suivies. Si ce n'est pas le cas on tombe dans un puits (sans fin) d'exceptions. Pour plus d'informations sur ce point, je vous recommande le très bon article de Charles Nutter sur le sujet.
Ainsi, ces limitations devrait disparaître avec l'ajout du support de la JSR 292. Celle-ci est déjà disponible depuis le JDK 6 update 16 et dans le JDK 7. Ainsi, les langages à typage dynamique devraient être plus rapides que sur la JVM actuelle, tant qu'ils ont pris en compte les ajouts apportés par cette JSR.
La JSR 292 apporte deux nouveautés :
Le détail du fonctionnement d'invokedynamic n'est pas très utile pour le développeur, donc je ne l'expliquerais donc pas. Concentrons-nous plutôt sur cette nouvelle API. Celle-ci comporte 6 classes importantes pour l'appel de méthode dynamique :
Voici un petit exemple d'appels dynamiques (tiré de l'article d'Ed Ort), qui montre comment générer et utiliser l'instruction invokedynamic :
import java.dyn.*;
public class Hello {
// Méthode qui va servir d'exemple pour les appels dynamiques
static void greeter(String x) {
System.out.println("Hello, "+x);
}
public static void main(String... av) {
// Appel "classique" de la méthode greeter
greeter(av[0] + " (from a statically linked call site)");
// On itère sur les arguments du programme
for (String whom : av) {
// Génère un invokevirtual MethodHandle.invoke(String)void
greeterHandle.<void>invoke(whom); // appel typé fortement
// Génère un invokedynamic MethodHandle.invoke(Object)Object
InvokeDynamic.hail((Object)x); // appel typé dynamiquement
}
}
//Création d'une signature de méthode : void maMethode(String)
static MethodeType methodType = MethodType.make(void.class, String.class)
// On fait le lien entre la méthode réelle greeter et
// notre signature de méthode methodType
static MethodHandle greeterHandle = MethodHandles.lookup().findStatic(Hello.class,
"greeter", methodType);
// Bootstrap du linkage
static { Linkage.registerBootstrapMethod("bootstrapDynamic"); }
// Méthode qui va effectuer la recherche et l'appel d'une méthode dynamique
//quand une instruction invokedynamic est trouvée
private static CallSite bootstrapDynamic(Class caller, String name, MethodType type) {
// Adaptation des types de type au handle greeterHandle
MethodHandle target = MethodHandles.convertArguments(greeterHandle, type);
//Fait le lien entre l'appelant (caller), le nom de la méthode (name) et sa signature (type)
CallSite site = new CallSite(caller, name, type);
// On donne au CallSite la méthode réelle à appeler
site.setTarget(target);
return site;
}
}
Le support de la JSR 292 est loin d'être terminé. En particulier, l'API n'est pas encore stable. Mais l'implémentation de cette JSR semble faire partie des nouveauté qu'apportera à coup sûr le JDK7.
Néanmoins, au moins deux projet supporte déjà cette JSR : Jython (depuis avril 2009) et JRuby (depuis septembre 2008). De plus, Charles Nutter, un des plus gros contributeur JRuby est aussi très actif dans la communauté du projet Da Vinci Machine.
Il semble donc que les communautés des langages dynamiques pour la JVM attendent avec impatience cette nouveauté, qui devrait leur apporter un gain important en terme de performance et de clarté de code. À suivre donc ...
Pour aller plus loin, vous pouvez trouver des builds du JDK 7 pour Windows, Linux et Solaris sur le site du JDK 7. Pour les possesseurs de Mac OS, la route est longue, très longue pour avoir un binaire, je vous fournis donc un petit how-to pour simplifier et compiler les choses :
hg clone http://bitbucket.org/pmezard/hgforest-crew/
[extensions]
hgext.forest=/path/to/forest.py
mq=
hg fclone http://hg.openjdk.java.net/bsd-port/bsd-port sources
cd sources && sh davinci-build.sh