Since 2005 or so, the Java virtual machine (JVM) has become a popular platform to host more than just Java code for execution. Other language developers rely upon the "write-once, run-anywhere" nature of the JVM (as well as other advanced features) to provide the runtime environment for their own languages. In fact, porting language interpreters to the JVM became so popular that Sun hired high-profile language developers Charles Nutter (JRuby), Ted Leung (Jython), and others to accelerate the porting efforts.
- Consolidation: The Foundation for IT Business Transformation
- Build a Business Case: Developing Custom Apps
- Client Windows Migration: Expert Tips for Application Readiness
- OpenStack: Blueprint for Deployment Success
Why have so many languages, including Ruby, Groovy, and Python, been ported to Java? Mainly because it's much easier to target one platform (Java code, in this case) and rely on the multiplatform JVM to host it than it is to write interpreters for each operating system. In addition, with the JVM's advanced just-in-time compilation, the resulting compiled and optimized Java bytecode typically will run with equal or better performance than native interpreters. Further, the Java JIT compiler continues to optimize code well after it's first compiled, depending upon changes in code execution and branching. The cost and effort associated with building this performance optimization into each independent interpreter implementation is prohibitive, so it makes sense to leverage the JVM's existing multiplatform implementation.
The JVM has other useful features, such as a large set of well-tested libraries, garbage collection, and excellent built-in tools and debugging interfaces that a language developer can easily plug into.
Bridging The Gap
Although writing language interpreters in Java offers huge benefits in terms of performance and multiplatform support, the biggest win is the interoperability it provides. For instance, Ruby code executing on the JVM is readily callable from a Java application, and vice versa. As a result, entire libraries of Java code, in source or JAR form, are instantly available to developers building applications in these other languages. Conversely, Java developers can experiment with code written in these other languages as well.
However, prior to the release of Java SE 7 last year, there was a small performance penalty when calling to and from the ported languages, such as when calling Ruby code from a Java application, or Ruby code calling into Java classes in a JAR file. This was mainly because the JVM wasn't initially built to support dynamically typed languages. To eliminate the performance penalty, the JSR-292 initiative was started with the goal of creating a new binary instruction (bytecode in Java nomenclature).
The result was the
invokedynamic bytecode, which is a JVM enhancement that allows dynamic and direct linkage between the calling code and the called code at runtime. With Java 7, invoking code in other languages is now equivalent to calling straight Java methods.
You can put languages ported to JVM into three categories: those whose primary goal is to improve Java, those that are ports of existing languages, and a miscellaneous category. All the of them are open source, and they fall out roughly this way:
- Better Java: Groovy, Scala, Kotlin, Fantom, Gosu, NetRexx (the original JVM scripting language);
- Ported languages: JRuby (port of Ruby), Jython (port of Python), Clojure (modified port of Lisp);