Last week SpringSource announced the release of Groovy 2.1.
With this release, Groovy adds several new features:
- Full support for the Java 7's invoke dynamic
- Goes beyond conventional static type checking capabilities with a special annotation to assist with documentation and type safety of Domain-Specific Languages
- Additional compilation customization options
- A meta-annotation facility for combining annotations
- GPars 1.0, the concurrency framework that is characteristically Groovy.
InfoQ interviewed Guillaume Laforge, Head of Groovy Development at SpringSource, to learn about some of these changes and about Groovy's general success.
InfoQ: How did invokedynamic simplify the development of the Groovy runtime?
Laforge: We can't yet really say that invokedynamic simplified the development of the Groovy runtime, in the sense that we still feature our usual call-site caching techniques for making our dynamic runtime fast, because we want our users to still be able to use JDK 5 or 6. Implementing invokedynamic hasn't been that simple, as the various JDK 7 updates have not always been totally stable and flawless. Fortunately this situation has greatly improved as the underlying VM implementation and APIs have matured. So it's going to be in future versions of Groovy, like Groovy 3, where we'll be invokedynamic only, requiring JDK 7 as the lowest possible JDK. Then we'll be able to get rid of our own old tricks, rather than having those two code paths in our codebase.
InfoQ: Has invokedynamic produced a perceptible improvement in performance?
Laforge: Invokedynamic allowed us to be more efficient, in particular in terms of memory footprint, as we don't need to generate as many classes at runtime and thus use less memory. Regarding performance, we've noticed some notable improvements in performance. It's difficult to give you a percentage as it varies greatly from one micro-benchmark to another.
InfoQ: What use cases would we most benefit from this performance improvement?
Laforge: Groovy was already using primitive type calculations routines, so for those math heavy benchmarks, Groovy was running pretty much as fast as Java already so invokedynamic is not expected to be much faster than what we had already.
Code that's heavy on method invocations produces the best improvements, and in some circumstances method invocation can be twice as fast! Also the results varied greatly depending on which update of JDK 7 we were using. Overall the results are good and we're happy with invokedynamic.
It also helped us optimize our codebase in various areas, so that it benefits users who are not lucky enough to run JDK 7. Ultimately, for our dynamic code, invokedynamic allows us in many situations to be as good as our old optimization techniques, without having most of their disadvantages. And if you're using the static compilation features that we added in Groovy 2.0, your code can be as type-safe and fast as Java.
InfoQ: What is your process for introducing or rejecting new language constructs, to maintain a readable language?
Laforge: Language evolution is an interesting question. Over the years, we've become stricter about language additions, as we don't want the language to become too complicated to understand and use. Also, we tried to stick to some basic principles of readability and conciseness.
First and foremost, we've always wanted to stay close to Java's syntax, so that Groovy would always be easy to learn and to pick up by new developers, coming from a Java background. It is said that any Java developer is actually a Groovy developer without knowing it!
Secondly, we didn't want brevity to make the language cryptic. We've always wanted Groovy to be a language that is easy to read and maintain. That's why, for instance, we don't allow the creation of ASCII-art operators that nobody would be able to decipher.
So with the help of the community, we're always trying to come up to a consensus in terms of language features, to find a good balance between conciseness, effectiveness and readability in order to keep the language elegant and a joy to use.
InfoQ: invokedynamic obviously required you to rip out the guts of some hairy code. What kind of testing is done to avoid regression issues?
Laforge: Over the years we've accumulated lots of test suites consisting of use cases coming from our user base, framework developers, etc., to tighten the solidity of the implementation in order to avoid backward incompatibility as much as possible. We're running all of our test suites across various system environments and JDK versions to ensure a high level of quality and backward compatibility.
InfoQ: What are some of the other compilation customization optimizations introduced in 2.1?
Laforge: Groovy 2.1 introduces some new refinements in terms of compilation customization.
Groovy is a great fit for implementing Domain-Specific Languages, and for that purpose Groovy comes with various tricks in its bag to allow developers to manipulate the code that is being compiled. You can hook into the compilation process to transform the code (what we call "AST transformations", think of them as kind of compilation macros), for example by adding new methods, by adding imports, or by limiting the syntax elements.
What Groovy 2.1 does is that it simplifies the process of configuring the compiler to apply those techniques by allowing you to use a special purpose DSL (a Groovy "builder") to describe the configuration of the compiler, and also by letting users specify the location of a script containing that customization, that you can pass to the Groovyc compiler.
Ultimately, our goal is to simplify the life of developers and framework authors who want to further leverage the Domain-Specific Language capabilities of Groovy.
InfoQ: Can you discuss the new meta-annotation features?
Laforge: Annotations are put to good use in the Java ecosystem. But sometimes you use too many of them and so for a simple field, method or class, you can have half a dozen annotations declared.
In the Groovy ecosystem, we rely on annotations to trigger some AST transformations, and a given set of classes (like an application's domain classes) could require the same set of such annotations all the time. So you might want to factor several annotations into one. That's how the idea of a meta-annotation system came.
Some frameworks (for example the Spring Framework) offer some facilities for defining meta-annotations. It's usually a specific solution to that framework, and we wanted something more general, that could be applied regardless of a particular framework.
So what we're doing here is that the meta-annotations are actually replaced at compile time, by the annotations they are combining. That way the classes, fields, methods, and parameters have the combined annotations on them, instead of a meta-annotation that would need to be handled by a framework at runtime.
In the end, with meta-annotations, you can make the code more readable and expressive, by providing some higher-level annotations that combine others, but at compile-time rather than runtime.
InfoQ: What features may we look forward to in the next Groovy major release?
Laforge: In the next major versions of Groovy, we haven't yet scheduled any particular important language features. We obviously have some ideas for a couple of new features But for the most part we will focus more on the architecture and implementation of the language, its dynamic heart, its compilation backend, its grammar, etc.
We are currently sketching a prototype for a completely rewritten dynamic backend (our "Meta-Object Protocol"), fully based on invokedynamic, in order to squeeze even more performance out of the JVM and rationalize our dynamic features.
Later on, we're going to rewrite the grammar of the language with a the newly released Antlr v4 parser generator, in order to make syntax evolution easier going forward and make our grammar easier to maintain.