Categories
Design Groovy

A Quick Catch-all Comparator Closure for Groovy

I don’t come from a functional programming background. As a result, the concepts of closures, currying, and so forth that are present in Groovy are taking some getting used to. But that’s half the fun 😉 And without even trying, I was able to come up with a practical use for both: a generic, catch-all comparator for sorting java.util.List instances.

First, let’s imagine we have a standard POGO (Plain Old Groovy Object) named User:

class User {

    String name

    String emailAddress

    Date dateOfBirth

    int weight

    String toString() {
        name
    }

}

Pretty standard fare, right? As often happens with many POJOs/POGOs, our class ends up being stored in instances of java.util.List:

def frank  = new User(name:"Frank Thompson", dateOfBirth: new Date(75, 0, 11), weight:150)
def bob    = new User(name:"Bob Turner", dateOfBirth: new Date(67, 4, 9), weight:115)
def james  = new User(name:"James Van Klein", dateOfBirth: new Date(58, 11, 13), weight:175)
def brad   = new User(name:"Brad Franklin", dateOfBirth: new Date(105, 7, 23), weight:25)

def userList = [frank, bob, james, brad]

And, as often happens with lists, they end up begging to be sorted.

The problem I found myself with was a desire avoid having to write N java.util.Comparator implementations “by hand” in order to sort a list by N different attributes of a class. That is, I know that most Comparator implementations in Java end up looking more or less like this fictitious implementation for our User‘s name attribute:

public class UserNameComparator implements Comparator<User> {

    public int compare(User a, User b) {
        def aValue = a.getName();
        def bValue = b.getName();

        if (!aValue && !bValue)
            return 0;
        else if (!aValue)
            return -1;
        else if (!bValue)
            return 1;
        else
            return aValue.compareTo(bValue);
    }

}

Having to duplicate that same logic for the emailAddress, dateOfBirth, weight, and so on — just for this one little class — seems overkill. And, it’s inevitable that many other classes would need to do the same thing…

This seemed like a perfect chance to use some of Groovy’s dynamic qualities to achieve a generic, reusable Comparator. Using Groovy’s closures and currying, I was able to come up with a simple sort closure that allowed comparisons on arbitrary attributes of a class:

def sortClosure = { attribute a, b ->
    def aValue = a.@"${attribute}"
    def bValue = b.@"${attribute}"

    if (!aValue && !bValue)
        return 0
    else if (!aValue)
        return -1
    else if (!bValue)
        return 1
    else
        return aValue.compareTo(bValue)
}

Here we take the attribute which is the name of the class’ instance variable/property/attribute to sort upon. a and b are the two instances of whichever class we happen to be sorting. We simply “curry” the name of the attribute, then pass the curried closure to the standard sort method of java.util.List:

println "Sorted by name: ${userList.sort(sortClosure.curry('name'))}"
println "Sorted by email address: ${userList.sort(sortClosure.curry('emailAddress'))}"
println "Sorted by dob: ${userList.sort(sortClosure.curry('dateOfBirth'))}"
println "Sorted by weight: ${userList.sort(sortClosure.curry('weight'))}"

And the best part is that this closure can be used to sort on any exposed attribute of any class.

So there’s a quick examples that shows closures and currying in practice. But of course there are a lot of very practical uses for both closures and currying beyond that, many which are less trivial and even more time saving.