Monday, October 22, 2012

Using Core Groovy AST Transforms

Have you ever used an Abstract Syntax Tree (AST) transform? If you're using groovy or grails, chances are you have, and maybe you just didn't know it. An AST allows code to be modified at compile time. Groovy provides the capability to write both local (annotation driven) and global (globally applied) AST transforms. They have a nice tutorial http://groovy.codehaus.org/Compile-time+Metaprogramming+-+AST+Transformations.

Even if writing AST transforms is not something you are doing, you can benefit from the numerous built in transforms that groovy provides. Many of these help to eliminate the need for boilerplate code that we've all written before. This post does not aim to list all of them, but rather to provide you an overview of some of them. Check out all implementors of the ASTTransformation from the groovy api (http://groovy.codehaus.org/api/org/codehaus/groovy/transform/ASTTransformation.html to see a full list.

Consider a Money class that looks

class Money {
    int amount
    String type // USD, Euro, etc

    boolean equals(Money other) {
        if ( other == this ) {
            return true
        }
        if ( other instanceof Money ) {
            return amount == other.amount && type == other.type
        }
        return false
    }

    int hashCode() {
        return new Integer(amount).hashCode() + type.hashCode()
    }
}

This is fairly verbose at best, and at worst, it's very error prone. What if I add a new field to the Money class and update the equals but forget to update the hash code (yes, tests should catch this). What if I forget to add the field to equals and hash code all together?

In Java, you might use Apache Commons' EqualsBuilder and HashcodeBuilder's reflection methods. This certainly simplifies your code, but the performance can be pretty bad if these methods are called frequently.

Enter the AST transform.

@EqualsAndHashCode
class Money {
    int amount
    String type // USD, Euro, etc

}

The @EqualsAndHashCode annotation adds the code at compile time, so you don't take the runtime hit, but you get the benefit of not having to write the code yourself.

Some other useful transforms include
@ToString - Adds a toString method
@Bindable - Adds property change support
@Mixin - Mixes in code to classes

As you can see, AST transformations can provide a lot of benefit and reduce the amount of boiler plate code you need to write. If you haven't used them before, I encourage you to at least take a look.

1 comment:

  1. This is great that it's done at compile time. Too much dynamism makes apps slower.

    ReplyDelete