Groovy

Updated 7th August 2006 - It looks like closures aren't meant to require K&R bracing after all. Hoorah! Examples changed appropriately.

One of my tasks at work is to investigate new languages and technologies and report back what use we might make of them, where they fit in with what we're doing, and generally what I think of them. Obviously some of this will be specific to Clearswift, but I'd like to make as much "insensitive" information available as possible. This post is my first "report" as such, on Groovy.

What is Groovy?

From the Groovy home page:

Groovy is an agile dynamic language for the Java Platform with many features that inspired languages like Python, Ruby and Smalltalk, making them available to Java developers using a Java-like syntax.

That doesn't help much if you don't know Python, Ruby or Smalltalk. However, the key words (for me at least) in the above are Java and dynamic. The Java bit is important to me because I know Java pretty well - both in terms of the language and the standard library. It's always nice not to have to learn yet another way of doing the same things. (There are extra things to learn in Groovy, but they are small in comparison with learning a platform from scratch.) The dynamic bit is important because it's what differentiates Groovy from Java in the first place.

Compared with, say, C and C++, Java is already pretty dynamic. It's very easy to load classes on the fly (it's pretty easy to generate them, even) and reflection allows you to examine classes at runtime. This allows for frameworks like Spring, Hibernate and JUnit. However, Groovy allows "dynamic typing" (an oft-contended phrase, but more later) and various bits of what are effectively syntactic sugar to make the code terser. Most importantly from my point of view, it offers closures - the equivalent of C# 2.0's anonymous methods. (This removes the need for most inner classes in Java.) There are various other handy features too, which generally make Groovy simpler to work with. Most of this post is effectively just a list of features with examples and discussion.

Compiled, but scripty

Groovy is compiled to Java byte-code, but can be written as a script as well. Normally, the whole script is compiled at start-up (as far as I can tell), although a lot of decisions are left to run-time, so typos etc can sometimes only show up when a line is executed, even though in a more "static" language they would have been caught at compile-time. Groovy scripts are (commonly) executed using the groovy tool. There are also tools for running Groovy as an interactive shell (groovysh) and a similar tool wrapped up in a GUI (somewhat confusingly called groovyconsole). The groovyc tool is provided to compile Groovy into bytecode to be used later rather than just run immediately. The input to the compiler doesn't have to be a fully-fledged class as such - it can just be a normal Groovy script, in which case a class with an appropriate Main method is created.

It's customary at this point to have a "Hello World!" program. As you can use Groovy like a scripting language, it's particularly simple:

println "Hello World!"

Saving the above to a file (e.g. test.groovy) and invoking with groovy test.groovy gives the expected result. Things to note:

  • No class declaration, import statements etc. It's just a script.
  • println is used instead of System.out.println. I believe this is a call to the println method which has been "added" to java.lang.Object.
  • No brackets and no semi-colon. You can use them - you can make them Groovy like very much like Java for the most part, but you don't have to. I tend to use brackets but often omit semi-colons. You don't even have to use brackets when there are multiple parameters.

As programs like the above are so convenient, I'm likely to use the features listed there in the samples below. Other than that, I'll attempt to only use one new feature at a time where possible, so it's obvious what I'm demonstrating.

Closures

In my limited experience with Groovy, closures form the single most useful feature of Groovy. They allow you to specify some code (which may take parameters and return values) and then encapsulate that code as an object - so you can pass it as a parameter to a method, for instance. The method could then call the encapsulated code, and so forth. C# 2.0 provides this feature in the form of anonymous methods (as delegate implementations) but in normal Java one would typically use an anonymous inner class, which can end up being very ugly due to all the extra "gubbins" of specifying the superclass and then overriding a particular method. Here's possibly the simplest example of a closure:

Closure c = { println ("Hello closure!"); }
c();

Giving all the details of what closures can and can't do would take pages and pages, so I'll just mention a few broad points. Local variables are captured as in C#'s anonymous methods (so are writable, unlike local variables being used in anonymous inner classes in Java), and access to private members of the enclosing class is also permitted. Closures taking a single parameter can use the implicit parameter name of it:

Closure printDouble = { println (it*2) }

printDouble(5)
printDouble(10)

Closures taking more than one parameter can specify their names in a sort of "introductory section":

Closure printProduct = { x, y -> println (x*y) }

printProduct (2, 3)
printProduct (4, 5)

Finally, a very common idiom in Groovy is to make the last parameter of a method a closure. In this case, you can call the method specifying all the other parameters normally, and then specifying the closure parameter as code which appears to be after the method call. This takes a little while to get used to, but is really, really handy. Here's an example:

// Declare the method we're going to call
void executeWithProduct (int x, int y, Closure c)
{
    c(x*y);
}

// Call it with a closure that prints out the result
executeWithProduct (3, 4)
{
    println (it);
}

Groovy uses closures extensively, so they will come up out of necessity in a lot of the following examples.

"Loose typing"

Groovy doesn't require you to specify the types of variables very often. Lots of magic happens to convert things at the right time. Indeed, method overloading appears to be performed at run-time rather than compile-time. The exact nature of how loose the types are is currently a mystery to me, and the specification is somewhat inadequate in this regard. However, it's worth looking at a few examples:

Simple hello world using loose typing (the differences when you use def are beyond the scope of this introductory article):

a = "Hello"
def b = " World!"
println (a+b)

Dynamic method overloading:

void show(String x)
{
    println ("string: "+x)
}

void show(int x)
{
    println ("int: "+x)
}

void show(x)
{
    println ("???: "+x)
}

y = "Hello"
show(y)
y = 2
show(y)
y = 2.5
show(y)

Results:

string: Hello
int: 2
???: 2.5

String interpolation

Groovy uses the GString class (I kid you not) for string interpolation. Double-quoted strings are compiled into instances of String or GString depending on whether they contain any apparent interpolations, and single-quoted strings are always normal strings. (If you need a character literal, it looks like you need to cast.) Any Groovy expression can be part of the interpolation, which is enclosed in ${...} (like Ant properties). The braces appear to be optional for simple expressions (the definition of which I'm not prepared to guess).

x = 10
y = "Jon"

println ('x is $x') // No interpolation with single quotes
println ("x is $x") // Simple interpolation
println ("y is ${y.toUpperCase()}") // Method call

Results:

x is $x
x is 10
y is JON

Collections: syntactic sugar and extra methods

Groovy makes working with collections easier, by providing syntax for lists and maps within the language itself, and by using closures to make life easier. List and map initializers both go in square brackets, with maps using a colon between a name and a value. Also, number ranges are available as start..end. Note that a number of common Java packages are imported by default, which is why the following code doesn't have to specify java.util anywhere.

List list = [0, 1, 4, 9]
Map map = ["Hello" : "There", "a" : "b"]
List range = 0..3 // Equivalent to [0, 1, 2, 3]

Indexers are provided (just like in C#) so using the above, map["Hello"] would give "There" and list[2] would give 4. The collections also have a number of extra methods added to them, many of them involving closures. For instance:

list = 1..7

// Execute the closure for each element
// Output: 2, 4, 6, 8, 10, 12, 14 (on separate lines)
list.each
{
    println (it*2)
}

// Find the first element where the returned value is true
// Output: 6
println list.find 
{
      return it > 5
}

// Find all elements where the returned value is true
// Output: [6, 7]
println list.findAll
{                    
    return it > 5
}

// Transform each element, creating a new list
// Output: [1, 4, 9, 16, 25, 36, 49]
println list.collect
{
    return it*it
}

There are more - see the link above.

IO

Another aspect of the JDK to be given the closure treatment is IO. Groovy makes it really easy to read each line of a file and execute some code on the line, for example. Here's a program which (assuming it's in a file called test.groovy) prints itself out with the line numbers:

int line=1
new File ("test.groovy").eachLine 
{
    println "${line}: ${it}"
    line++
}

Enhanced switch statements

In Groovy, switch statements can have cases which are collections (including ranges; the case matches if the switch value is in the collection), types (the case matches if the value is an instance of the type), regular expressions, and falls back to equality otherwise. In fact, you can add your own type of case testing by implementing an isCase method, making switch/case very flexible indeed. I haven't tested it, but I doubt this is nearly as efficient as the normal Java switch/case - but Groovy is about simplicity of expression more than ultra-efficiency.

Categories - aka C# 3.0 extension methods

Groovy allows you to pretend that a class has a method you wish it had. It's all pleasantly scoped so you won't do it accidentally. Here's an example:

// Define the extra method we want
class IntegerCategory
{
    static boolean isEven(Integer value)
    {
         return (value&1) == 0
    }
}

// Use it - in a cleaner looking way than
// explicitly calling the static method.
use (IntegerCategory.class)
{
    println 2.isEven()
    println 3.isEven()
}

Groovy Markup

There are many times when you need to build a hierarchical structure of some kind. Groovy introduces the idea of "builders" which help. For instance, for XML, there's the DOMBuilder class (along with SAXBuilder and NodeBuilder, the latter of which allows easy XPath-like navigation). Using DOM to build XML in Java is a complete nightmare, and while dom4j and JDOM are definite improvements, they still don't make it quite as easy as this. Suppose you have a map of names to ages, and you want to build an XML document representing that information. Here's a sample script in Groovy to demonstrate how easy it is (using MarkupBuilder, which writes the generates XML out for you). Elements are added just by calling a method of the same name (Groovy responds to the method call as if the method were available normally, even though obviously it doesn't know in advance what your element names will be), and attributes are specified using a map in the method call. Child elements are specified within closures.

import groovy.xml.*;

Map nameAgeMap = ["Jon": 29, "Holly": 30, "Dave": 32]

builder = MarkupBuilder.newInstance()
builder.rootElement
{
    names
    {
        nameAgeMap.each 
        {
            entry ->
            person ("name": entry.key, "age": entry.value)
        }
    }
}

Result:

<rootElement>
  <names>
    <person name='Holly' age='30' />
    <person name='Dave' age='32' />
    <person name='Jon' age='29' />
  </names>
</rootElement>

Ant integration

I'm a big fan of Ant, but every so often it just doesn't let me do everything I want easily. Sometimes I want to be able to execute some code, but I don't want to go through the hassle of having to make sure I've compiled something which is only actually going to be used by the build procedure anyway. Groovy to the rescue! You can embed Groovy code "in-line" or call out to a Groovy script. Note that Ant allows many scripting languages (anything supported by BSF, for starters) to be used. Groovy may be more familiar-looking to developers who are familiar with Java but don't know any scripting languages. Groovy supports Ant directly in terms of providing access to the current project and properties, and the AntBuilder class works in a similar way to the builders mentioned above, allowing Ant tasks to be dynamically created and executed. Here's a sample Ant file (which assumes that groovy-all-1.0-jsr-05.jar is in the same directory):

<?xml version="1.0" ?>   
<project name="groovy-test" default="test" >

  <taskdef name="groovy" 
         classname="org.codehaus.groovy.ant.Groovy"
         classpath="groovy-all-1.0-jsr-05.jar"/>
  
  <target name="test">
    <groovy>
      println "Running in Groovy"
      
      fs = ant.fileset (dir: ".", casesensitive: "no") 
      {
          include (name: "*.groovy")
          include (name: "*.java")
          exclude (name: "Test.*;test.*")
      }
      
      fs.toString().split(';').each 
      {
          ant.echo (it)
      }
    </groovy>
  </target>                               
  
</project>

Results:

Buildfile: build.xml

test:
   [groovy] Running in Groovy
     [echo] Benchmark.java
     [echo] CommandTest.java
     [echo] Handler.java
     [echo] Main.java
     [echo] MyEnum.java
     [echo] test2.groovy
   [groovy] statements executed successfully

BUILD SUCCESSFUL
Total time: 1 second

Other bits and bobs

There's a lot more to Groovy than what's presented above. It has operator overloading, syntax to make regular expressions and multi-line strings easier, simple property definition and access, built-in JUnit integration, an XPath-like expression language and much more besides. Read the home page for some of these - but be warned that some features are pretty well hidden.

So, what's wrong with it?

In general, I like Groovy. I'm not convinced that the productivity gains from it are worth the downsides for major apps, but it's really handy for getting something small working quickly. It could be really great for prototyping. I may well eventually be convinced that "dynamic typing" isn't that dangerous really, and doesn't have a detrimental impact on the usability of libraries, etc. Only time will tell.

In the meantime, however, Groovy does suffer majorly from a lack of polish. There are plenty of bugs to be found, and the documentation is terrible. (The members of the mailing list are more than happy to help, and a major documentation update is under way, however.) There are aspects of the syntax which seem to be overkill, creating complexity without a huge benefit, and there are bits of normal Java which are just "missing". (Normal for loops aren't available in the version I'm using, although I believe they will be in the next available release. You can use a loop such as for (i in 0..9), but not for (int i=0; i < 9; i++).) Things like this should really be fixed to make as much of normal Java as possible available within Groovy.

I don't mind the fact that Groovy isn't finished - my worry is that it may never really be finished. I really hope that I'm wrong, and that it will be all done and dusted (for v1) in the summer. There's no lack of activity - the community is very lively - but activity doesn't necessarily indicate actual progress towards a goal. Since originally posting this blog entry, I have been assured that real progress is being made, so I'm keeping my fingers crossed.

Links

  • Groovy home page
  • "Groovy JDK" - the extra methods added to various classes
  • Grails - Groovy/Spring/Hibernate-based web application devlopment
Published Thu, Apr 20 2006 23:40 by skeet
Filed under: ,

Comments

# re: Groovy

My experience using Groovy in real world app, with about 30000 SLOC, is that there really wasn't much in terms of bugs. Most of the bugs I've read about tend to be corner case stuff. For our project, it's never escalated to the point where it became an item on a project plan or project issue list.

The app I've built had a strict performance requirement and I must say that Groovy performs surprisingly well. It became an issue for us in one math calculation that is called literally thousands of times. We rewrote the calculation in Java and everything peforms great. Having this flexibility as a saftey net I think is one of Groovy's strengths.

The biggest productivity gain I've seen was that the resulting code was more readable - there was a lot less clutter. One area you didn't highlight was how Groovy doesn't make you put try-catches around everything that can throw an exeception.

When I was evaluating languages, I took some existing code (4 modules with a total of 100-150 SLOC) from a real project and rewrote it the languages I was evaluating. For our app, the new functionality around collections and automatically handling of exceptions that we really didn't care about had a dramatic impact.

Friday, April 21, 2006 8:52 AM by Scott

# Groovy 1.0 released

Groovy 1.0 has finally been released, and is available for download from the Groovy home page . For those

Wednesday, January 03, 2007 1:20 PM by Jon Skeet's Coding Blog