Tuesday, March 11, 2008

Groovy is Java AND Groovy is not Java

There is a new dynamic language shootout featured on InfoQ where Groovy comes out on top as the JVM language of choice for a variety of reasons and one of the reasons cited was that it is a near superset of Java. Queue the comments from the Ola Bini brigade that:

"If you're going to use Groovy the same way you use Java, there is absolutely no gain. Just a performance hit."

However, this sadly is missing the point. Sure, if you write Groovy like Java you get no real benefit, but it provides that migration and, crucially, learning path onto a Groovier way.

Learning a programming language is for the most part trivial and can be achieved in a few days. Learning the libraries is what takes the time. Groovy shares the same Java APIs as standard Java, you know things that you know and love like java.io.File, java.lang.String etc.?

The real difference comes in what it adds to these standard libraries through the GDK. For example great stuff like this:

myFile.eachLine { println it }

def contents = new URL("http://google.com").text

def list = ['a','c','
b']
list = list.collect { it.toUpperCase() }.sort()

def text = "Hello World"
text = text - "World"
println text // prints "Hello "
println text[0..-3] // prints "Hell"

Once you learn the "new way" combined with meta-programming capabilities that Groovy has on offer you'll never look back.

Scott Davis came up with a great quote to describe this at the recent 2GX: Groovy/Grails Experience:

"Groovy is Java AND Groovy is not Java at the same time"

In other words, you get the best of both worlds.

11 comments:

Paul Barry said...

But Groovy is not Ruby. One feature of Ruby is to be able to call methods during the process of class definition, which can add methods to the class being defined. This is used in ActiveRecord for things like defining the belongs_to relationships. In GORM, you have to declare a static property (which acts as the equivalent of an annotation), which something else comes along and reads and uses to add methods to the class. The Ruby way seems cleaner and more powerful to me. Am I wrong?

Graeme Rocher said...

Yes that is a nice feature of Ruby. I wouldn't say its better, just different

Also note that to get the ActiveRecord magic happening you have to extend the ActiveRecord class, essentially binding you to the framework.

GORM requires no inheritance, in fact it doesn't care if its a Java or a Groovy class as long as it exists in Hibernate it adds the magic. That seems cleaner and more powerful to me. Am I wrong? ;-)

Paul Barry said...

@Graeme

I agree having to extend the ActiveRecord Base class is unnecessary. DataMapper, another Ruby ORM, doesn't require you to extend a base class, you can just mixin a module, but in practice you end up extending from a base class anyway, because it doesn't cause any problems. DataMapper also has you define the properties in the model, rather than the database, which is another thing a lot of Java/Hibernate programmers tend to hate about ActiveRecord. I bring that up because a lot of times in these Java/Groovy vs. Ruby debates, things about specific frameworks like ActiveRecord get brought up, which have nothing to do with the language itself.

I don't think having ORM-neutral classes and being able to swap out ORM frameworks with no changes really buys you anything. But you may want to have your own class hierarchy, so not extending a base class could be nice in some situations, but most of the time it just doesn't matter.

In Java, not having to inherit from certain classes is a big deal, but in Ruby, it just doesn't matter as much. I suppose it's combination of mixins, duck-typing and meta-programming that make that the case.

Michael Easter said...

re: scott's quote.

Delightful. Very much like a Zen koan.

I can envision an entire talk based on some Zen paradoxes that illustrate the Groovy Way.

tug said...

The way I explain the relationship between Groovy and Java is as follows:

I speak and understand English I also speak and understand (computer) Jargon.

Speaking and understanding English gives me easy access to an incredible resource.

Speaking and understanding Jargon allows me to communicate with speed and precision with other Jargon speakers. I get more done in less time and have fewer misunderstandings. I can have exactly the same interaction with English speakers but I have to use very many more words, and make more mistakes.

Jargon is, of course, English but it's English in a context.

Java is English, Groovy is English + Jargon

Willy said...

The original post makes an important point when saying 'I think Grails is on its way, if it doesn't get usurped by the Java platform desire to make everything unbearably complicated.'

Certainly one of the aspects that make Grails superior to Rails is that integrates very well with existing enterprise software and enterprise requirements in general while remaining simple to use at the same time.
In contrast to that Rails guys more often than not simply state that 'If you don't do it our way, then, sorry, Rails is not for your.'

However, the Grails community has to beware of 'enterprisey' features slowly creeping into the framework as the standard way of doing things.

While there is nothing wrong with supporting these as well, Grails' main objective IMO should always be to keep things simple and productive.

Ricky Clarkson said...

"In other words, you get the best of both worlds."

Minus static typing.

Anonymous said...

@Ricky

Which is truly the best of both worlds. :)

Ricky Clarkson said...

@Anonymous

It's good to detect errors statically. This is valid Groovy code that throws an exception: int i="hello" - I'm not sure why that should be a runtime error when you can establish that the error will happen just by looking at the source code.

Anonymous said...

I guess it all boils down to where you're moving the ball of hair. convinience to the programmer doesn't always translate to convenience to the end user...

Sometimes what you gain in productivity up front is taxed (plus interest) in maintenance cost.

Personally, I think Ruby/Rails trying to move Java people to their camp is a mute point. Few Java developers would throw away their investment in learning and tools. If I want to do scripting, Groovy is more than good enough.

To me, the real value with Groovy is in Grails though. Through plugins I can integrate just about any Java solution, pretty effortless :)

/java-dude

Unknown said...

Hi Graeme,

i’ve seen your blog and i think that you can give me a response about a script in Groovy.
I have think to a new programming style using Groovy and Closures.
The script is:

Code
———–

/*
Give a structure with N array containing data, the code analyze each array contained and
if elements number major 5 do this:

sumElementList, storeSumInCache, printSum

else if minor:

sumElementList,printSum

look at SKELETHON section is the main part of code and can make reading a program more readable.

———–
*/

// ### DECLARATION ELEMENTS ###
def cache = new ArrayList()
def structure = [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 2, 3, 4]]
def elementList = structure[0]
def sum = 0;

// ### DECLARATION GENERIC CLOSURES ###
def execute = {
Object[] closures ->
def currentClosure = null;
closures.each() {
currentClosure = it.call(currentClosure)
}
return currentClosure
}

def forDo = {
indexFor, Object[] closures ->
indexFor.times {
execute(closures)
}
}

// #### ACTIVITY : SOMMA ELEMENTI ####

def ifElementNumberMajor5 = {
Object[] closures ->
if (elementList.size() > 5) {
println ‘rilevato NumeroElementiListaSupera5'
execute(closures)
}
}

def ifElementNumberMinor5 = {
Object[] closures ->
if (elementList.size() <= 5) {
println ‘rilevato NumeroElementiListaNonSupera5'
execute(closures)
}
}

def sumElementList = {
println ‘ Closure [ sommaTuttiGliElementiDellaLista ]‘
elementList.each { sum += it }
sum
}

def storeSumInCache = {
println ‘ Closure [ memorizzaSommaInCache ]‘
if (!cache.contains(it)) cache.add(it);
it
}

def printSum = {
println ‘ Closure [ stampaSomma ]‘
println “stampo risultato somma $it”
}

def updateVariablesActivitySomma = {
println ‘ Closure [ aggiornaVariabiliActivitySomma ]‘
elementList = structure[index++]
}

// #### SKELETHON ####

index = 0
forDo(structure.size()) {
updateVariablesActivitySomma
ifElementNumberMajor5(sumElementList, storeSumInCache, printSum)
ifElementNumberMinor5(sumElementList, printSum)
}

———–
what do you think about this ?

Thank’s for response.

By

Giuseppe Astarita
Software developer
Telecom Software factory Division.