Web Development

Language of the Month: Groovy++, How Java and Groovy Can Be Better

By Alex Tkachman and Roshan Dawrani, May 17, 2011

Groovy's concise syntax and vaunted capabilities come at the cost of performance. Groovy++ solves this problem by adding static typing and several small features that bring performance on a par with native Java

During the last seven years, we have seen a real renaissance in programming languages on the JVM platform: Groovy, Scala, Clojure, JRuby, Jython, and Mirah to name a few. As a result, for many people today, the real meaning of word Java is not the programming language, as such, but the JVM as a platform: It allows software components written in all these different languages to interoperate as parts of the same application. We programmers have great freedom to choose the right tool for the job.

Of course, each language has its own benefits and downsides. Scala brings a lot of very interesting ideas on combining object-oriented and functional programming together with a much more powerful (but complex) type system, and a very different syntax from Java. Clojure, JRuby/Mirah, and Jython bring a charming taste of Lisp, Ruby, and Python respectively to JVM, which makes it easier for developers from these worlds run on the JVM.

Groovy brings Java developers a familiar, more convenient, and less verbose syntax along with a very powerful library for everyday work. Groovy is our personal favorite, but we might be biased as we are both members of the Groovy core development team.

Unfortunately for Groovy users, because Groovy is a fully dynamically typed language, it runs slowly, does not allow compile-time type checking, and limits the usefulness of static code analysis. This is where Groovy++ changes the game. Let's compare Groovy with Groovy++.

Groovy and Groovy++

Groovy is a popular and successful dynamic scripting language for the JVM. It has extended the Java platform in many exciting ways and brought powerful language features and frameworks to Java developers while remaining very close to Java at syntax and semantic levels. Groovy's powerful language features combined with its ease of use can soon become an addiction, and once you are addicted to it, going back and writing Java code can be a difficult thing to do.

The Groovy project website is a great source of information and references about the rich ecosystem around Groovy.

Groovy++ is a statically typed extension to the Groovy programming language (it's just one jar file to add to your project). It provides:

Both Groovy and Groovy++ try to achieve the same goal — letting Java developers be more productive without going too far from the syntax, tools, and technologies they already know. Groovy approaches this goal from a dynamically typed angle and Groovy++ completes the picture by providing the statically typed part of the story with the ability to mix both dynamic and static parts together.

If the Java programming language had evolved faster over the last five years, then it very well might look and feel similar to Groovy and Groovy++ combined.

Type inference and implicit casts

Although Groovy++ needs the type information for its static type checking, it uses local type inference technique and implicit type casts. This is a fundamental part of Groovy++ and acts as a guiding principle for everything else.

Type inference

Type inference reconstructs omitted type annotations (like String or List<String>) and aims at providing the same concise feel as dynamic Groovy. Because the goal of Groovy++ is to provide the static semantics as close as possible to the dynamic semantics, type inference differs from that found in most statically-typed languages.

There are many cases where Groovy++ infers your program's types:

variable declaration

closure parameters types

types of variables used in certain switch/case

method call arguments represented by list/map/closure expressions

parameters of overridden methods

Groovy++ does not allow the method return types or parameter types to be inferred, since they are considered an important part of the method contract and should be visually apparent.

Implicit casts

At times, the Groovy++ compiler complements type inference by doing the opposite operation: inserting implicit casts into the code when needed. This is done in the following cases:

assignment to typed variables/fields/properties

return statements (including implicit ones)

method arguments represented by list/map/closure expression

brunches of ternary expression, which are implicitly or explicitly cast to a type

In all cases, the compiler creates an error if the types are not convertible. Note that the convertibility rules are a bit more relaxed than in Java.

Listing One demonstrates implicit casts and type inference working together. The comments describe what is going on.

The @Typed annotation is a Groovy++ statement that tells the compiler that the whole script should be compiled statically.

Additional Productivity Features

There is more to improving Java than just type inference and implicit casts. Groovy++ strives to make development enjoyable and pleasant by adding more visible features to the language, extending not only Java, but Groovy as well.

List/map/closure expressions

There are three special types of expressions in Groovy++ that make the language more expressive to both Java and Groovy programmers:

Each of these expressions has the same meaning in Groovy and Groovy++: They create an ArrayList, LinkedHashMap, or groovy.lang.Closure, respectively. But in the situation of a type cast (including implicit casts) the meaning of the respective expressions are different and represent new instances of the required type. Any such transformations can lead to transformations of nested elements as well.

Let's explain this with a few examples without going into a lot of detail. Given this code,

[a, b, c] as T[] means: new T[]{(T)a, (T)b, (T)c}

the compiler verifies and checks each element of the list to tries to make sure that the elements are of the correct type. This is one example of how static typing is being brought into the dynamic Groovy language.

[a, b, c] as LinkedList<X>

means something similar to:

new LinkedList<X>().addAll((X)a, (X)b, (X)c)

Again, each element of the list is type-checked. This happens at compile time, not at run time, which catches many type errors earlier.

(Type)[a, b, c] means new Type(a, b, c)

Lists can be implicitly cast into constructor calls. This option opens interesting opportunities in combination with implicit casts. For example, CountDownLatch cdl = [1] is equivalent to CountDownLatch cdl = new CountDownLatch(1).

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task.
However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

This month's Dr. Dobb's Journal

This month,
Dr. Dobb's Journal is devoted to mobile programming. We introduce you to Apple's new Swift programming language, discuss the perils of being the third-most-popular mobile platform, revisit SQLite on Android
, and much more!