Elvis carried away by spaceships

Posted by: Kenneth Kousen on 01/13/2012

I love teaching Groovy to existing Java developers, because they have such a hard time holding back Tears Of Joy when they see how much easier life can be. Today, though, I did a quick demo that resulted in a line of Groovy that was so amusing I had to post it here.

Consider a trivial POGO (Plain Old Groovy Object) called Course:

class Course
    String name
    int days
    String toString() { "($name,$days)" }
}

The goal was to take a collection of courses and sort it by the number of days. That’s really easy in Groovy:
def courses = [
    new Course(name:'Groovy',days:4),
    new Course(name:'Grails',days:3),
    new Course(name:'Spring',days:4),
    new Course(name:'Hibernate',days:3)
]

assert courses.toString() == '[(Groovy,4), (Grails,3), (Spring,4), (Hibernate,3)]'

courses.sort { it.days }

assert courses*.days == [3, 3, 4, 4]

The sort method in the java.util.Collection class is part of the Groovy JDK, meaning it’s one of the methods Groovy adds to the standard Java libraries. It takes a closure of either one or two arguments. In this case, I’m using the one-argument closure, which is used to select a property on which to base the sort. By specifying it.days in the closure, I’m telling the sort method to sort the courses based on their days property. Then I verify that the sort worked by checking that the courses are the right order, using the spread-dot operator to just look at the number of days.

In class the question that always comes up is, can I sort by days and then by name? In other words, if two courses have the same number of days, can I then sort by the name property?

That’s what the two-argument closure on the sort method is for. The two arguments are references to any pair of courses, and the closure should return a negative number, zero, or positive number according to whether the first course is less than, equal to, or greater than the second.

Here’s where things get amusing. The sort I want is:

courses.sort { a,b ->
    a.days <=> b.days ?: a.name <=> b.name
}

assert courses.toString() == '[(Grails,3), (Hibernate,3), (Groovy,4), (Spring,4)]'

The body of the closure on sort uses the spaceship operator <=>, which returns -1, 0, or 1 depending on whether the left side is less than, equal to, or greater than the right side. I use spaceship to compare the days properties. Then I add the Elvis operator ?: which means if the days comparison is not zero, use it, but otherwise use the following comparison, which uses another spaceship to compare by name.

It’s only after writing the code in class that one of the students pointed out that I had Elvis in between two spaceships, leading to the following observations:

  1. The spaceships are there to return Elvis to his home planet
  2. It takes two spaceships, working in tandem, to carry Elvis away, in much the same way two swallows can carry a coconut in tandem
  3. Therefore, the Elvis being carried away must be the fat Elvis from the 70s, rather than the thin, cool Elvis from the 50s

Either way, after the sort is finished, Elvis has left the building.

Thank you, thank you very much.



About Kenneth Kousen

Kenneth Kousen

Ken Kousen is the President of Kousen IT, Inc., through which he does technical training, mentoring, and consulting in all areas of Java and XML. He is the author of the O'Reilly screencast "Up and Running Groovy", and the upcoming Manning book about Java/Groovy integration, entitled "Making Java Groovy".

He has been a tech reviewer for several books on software development. Over the past decade he's taught thousands of developers in business and industry. He is also an adjunct professor at the Rensselaer Polytechnic Institute site in Hartford, CT. His academic background includes two BS degrees from M.I.T., an MS and a Ph.D. from Princeton, and an MS in Computer Science from R.P.I.

More About Kenneth »

NFJS, the Magazine

May Issue Now Available
  • Client-Side MVC with Spine.js, Part 1

    by Craig Walls
  • On Prototypal Inheritance, Part 2

    by Raju Gandhi
  • Making use of Scala Lazy Collections

    by Venkat Subramaniam
  • Integration Testing Web Applications Using Gradle

    by Kenneth Kousen
Learn More »