What Is Groovy++? How Does It Compare With Java and Groovy?
While some find Groovy language still in its infancy, others know that there is now Groovy++ and are all eyes and ears on what “++” of the language is going to bring, which itself was touted by some as Java++.
I have been very curious to know about it since the first preview of Groovy++ was announced last year (was it that long ago? :-)). The initial releases that have come out have been supported by minimal (no?) documentation and there are now questions in the air, like –
- What is it trying to achieve?
- What should people look forward to, for what kind of things, and why?
- How is it going to work? Will be compatible with my existing groovy code?
While it is understandable that the documentation is lacking because Groovy++ project is very, very new, it doesn’t help. So, Instead of waiting for the documentation to become available, I tried to take a sneak peek into Groovy++ and find some answers for myself. Here is a little write-up of a few things that I understand so far. I hope it is of use to some of you.
Disclaimer: The content here expresses my understanding and opinion of the subject and is prone to human error.
So, why Groovy++?
On the small scale of a sneak peek, I don’t find it difficult to understand why Groovy++ is needed. I have used Groovy for some time now and while it has many wonderful features, every feature comes with a cost. Everyone has to bear the cost of the features, whether they are interested in using that feature or not.
To take a very small example, if I have “1 + 2” in groovy, to allow all the dynamism and flexibility of the language, very simply put, it becomes 1.plus(2) where you can change the behavior of “plus” and make “1 + 2” do “2 – 1”, if you want, and change the behavior of “plus” as many times at runtime as you want. So, what in Java is equal to a simple + operation, becomes a method call that goes through various checks to see if the behavior of the method has “now” been modified, and point it to the current definition of “+”. All of it comes at a cost on the performance, memory, etc, and if even in my dreams I never had an intention of overriding “+”, I still have to bear the cost associated with the relevant groovy infrastructure.
While the core groovy is always making efforts to reduce that cost, what is missing right now is a way to avoid the cost altogether.
To me, the biggest advantage of Groovy++ will hopefully be that it will let you strike a balance and avoid the cost of features that you don’t want to use – as far as possible – as it still has to remain groovy and not become Java. It will let you choose the parts of your program, where you want all the dynamism, flexibility of core groovy and are ready to pay for it in terms of performance, and other parts where you may do with lesser dynamism but need better performance and more compile time checks.
The picture that I had in my mind of Java->Groovy->Groovy++ at the time of Groovy++ announcement was like:
After a bit of sneaking, it is now changing to:
I like where Groovy++ is positioned and I wait for it to become mature and for more to come from the project.
What is Groovy++?
Q. Is it related to standard Groovy?
A. Yes, it is just an extension of the standard Groovy. Current releases of Groovy++ are using the red hot Groovy 1.8.x snapshots under the hoods. So, everything that you can do on the core groovy is available to you with a choice to go with groovy++’s static compiler for better performance wherever you want.
Q. Where can I find it?
A. You can download it from the Tests and standard library for Groovy++ site
Q. I have installed groovy++. How do I start using it?
A. The groovy++ top-up on core groovy lives in groovypp.jar that you find under lib folder in your installation directory. The way to start using it is to ensure it is on classpath and then use @Typed annotation that groovy++ provides. You can mark selected methods, classes or the packages as @Typed and only those get statically compiled by groovy++, while for everything else, standard groovy is used.
Q. How does it work on the inside? How can its integration with groovy be so simple?
A. It does so by hooking into the groovy compilation process – by defining an AST transformation, which gets kicked off from @Typed annotation usage. If you are not familiar with the basics of this technique, you may find the following article useful – Compile-time Metaprogramming – AST Transformations. Simply put, what it does is that :
- It intercepts the compilation process and then processes all the methods selected with @Typed – directly or indirectly through annotated classes/packages and runs them through its stricter compile time checks, type inference techniques, and
- Changes the AST, which is produced by groovy compiler until that point, to make it output bytecode that is less dynamic-dispatch based and hence, has better runtime performance.
Pros and Cons of using Groovy++
Q. What do I lose?
A. The runtime meta-programming behavior of groovy language, because the method dispatches become more direct and less dynamic.
Q. What do I not lose?
A. Most of the features of the groovy language are available “as-is” even with groovy++, for example –
- Groovy’s extensions to JDK classes
- Less verbose groovy coding
- Support for features like categories, mixins, closures
- Ability to hook into compilation through AST transformations
Q. What do I gain?
A. Things like:
- Better performance – through lesser use of dynamic-dispatch.
- Even less verbose code – through use of type inference
- Safer code – through use of stricter compile time checks
Comparing Groovy / Groovy++ through some examples
There are primarily 2 areas that groovy++ affects – performance and stricter compile time checks.
Since the changes it introduces for the performance improvement are mostly internal (in the bytecode that gets generated – details of which can be left for a later post), this section mainly tries to show some basic examples where the differences are more visible on the outside – to give a sense of stricter compile time checks and lesser use of dynamic-dispatch.
Example 1: (Static Compilation)
[groovy]
def addG(x, y) {
x + y
}
@Typed
def addGPP(x, y) {
x + y
}
println addG (2, 3)
println addGPP (2, 3)
[/groovy]
With groovy++, the compilation of the method addGPP() fails because the compiler does not statically know which plus() implementation to invoke based on the types of the parameters (groovy makes a number of “plus” implementations available and chooses the most appropriate one based on runtime types). In this case, groovy++ compiler cannot infer the types too.
Example 2: (Runtime meta-programming)
[groovy]
def addG(x, y) {
x + y
}
@Typed
def addGPP(Integer x, Integer y) {
x + y
}
// override plus to make ‘+’ do multiplication instead
Integer.metaClass.plus = {Integer other -> delegate * other}
// because groovy uses runtime meta-programming to see the modified "+"
assert addG (2, 3) == 6
// because groovy++ does not use runtime meta-programming and instead binds to "+" at compile time
assert addGPP (2, 3) == 5
[/groovy]
Example 3: (Performance)
While this example hardly does anything, the difference in the performance is still an indication of the direction Groovy++ is taking. The difference in more realistic usages can be significantly higher.
[groovy]
def addG(x, y) {
x + y
}
@Typed
def addGPP(Integer x, Integer y) {
x + y
}
// override plus to make ‘+’ do multiplication instead
Integer.metaClass.plus = {Integer other -> delegate * other}
def start = System.currentTimeMillis()
(1..1000000).each{
addG(2, 3)
}
def end = System.currentTimeMillis()
println "Groovy took ${end – start} milliseconds" // I got ~= 3.7 seconds
start = System.currentTimeMillis()
(1..1000000).each{
addGPP(2, 3)
}
end = System.currentTimeMillis()
println "Groovy++ took ${end – start} milliseconds" // I got ~= 1.8 seconds
[/groovy]
These are just a few very basic examples to highlight a few differences discussed in this article. I will try to cover a few more advanced examples and more details of Groovy++ in later posts.
Conclusion
I hope the article has served its purpose in introducing Groovy++ and whetting your appetite a bit. I feel that Groovy++ is positioned very well between Java and Groovy and I hope it will be able to strike the magical balance well and help Groovy become an even more mainstream language.
if you defined addGPP to be an actual static multiplication, the diff between an add and multiply would have been subtracted from the perf comparison. Granted, the operation time would be minimal, and micro-benchmarks are always suspect.