I'm a huge fan of Groovy, but it's major downside drove over me like a bus this evening. What's that, you say? Performance, of course. Runtime "stuff" necessarily happens at runtime, and therefore affects performance. Does this matter in most cases? No, absolutely not. In general it's far cheaper to buy hardware than to employ developers, so ease of development and maintenance almost always trumps raw performance. This is why we use high level languages as opposed to writing everything in assembler.
As you probably expect, I was working on Project Euler. Problem 39, to be specific. The algorithm is simple, and if you pay attention, you don't even have to do the full scan to get the answer. However, I couldn't get within the minute boundary with my algorithm. I did a whole bunch of optimizations to ensure I was doing absolutely as little work as possible (including stopping the search at the known answer!) and still couldn't even come close to the minute deadline.
On a whim, I took my brutish, unoptimized version (because the syntax was less Groovy-ish) and dropped it into a Java class. I had to add a pile of semicolons and variable types, insert a couple imports, and convert a GString, but the rest was untouched. Full scan (from 1-1000) in 172 milliseconds. Needless to say I was disappointed.
Am I going to abandon Groovy for Java? Hell no. But definitely going to consider reimplementing some of my hard-core subroutines in Java. Just another case of knowing your tools so you can pick the right one for the job. And just to be clear, I have no expectation that this sort of performance difference is in any way indicative of Groovy's general performance. In fact, I find Groovy to be ridiculously fast, in general, because I'm typically doing far higher-level operations (like using Hibernate).
One interesting point was that copy and pasting the Java version into a Groovy file and running it (with all the semicolons and explicit variable typings) didn't affect the Groovy performance much. That surprised me. Apparently the Groovy compiler treats 'int' as 'Integer' or something similar. I've never looked into it very deeply, but worth mentioning I thought.
Also interesting is that CFSCRIPT on CF 8.0.1 turns in times that are slightly faster than Groovy running through CFGroovy on the same page. I would have expected the reverse since CF uses java.lang.Double internally, but it seems the lack of unboxing/reboxing makes up for the floating point calculations.
Further reading: http://java.dzone.com/news/groovy-vs-java-performance-jav
Cool that cfscript is faster, who woulda thunk it? =]
Are you using version 1.6?
DT,
No, still running 1.5. I created the project back in early February and haven't upgraded since the release. I know it's supposed to be significantly faster, but haven't given it a whirl yet. The Eclipse plugin is still serving 1.5.7, and I haven't dug into figure out how to set it up with a different JAR.
DT,
Over lunch I stuck Groovy 1.6 in there. It knocked about 20% off the execution time versus 1.5.7 for the specific test I was doing. Brought the fully optimized version down to 1:20, so still not fast enough to break the minute barrier. On the same machine, the unoptimized Java takes right about 110ms.
You are correct, speculating that there are no primitives such as int.
Just last night I was reading that everything is an object in Groovy. If you declare something as a primitive, Groovy will silently wrap it in a class such as Long, Integer, etc.
Jim,
That makes sense. I'd expected it to work more like Java, where the wrapping happens on-demand (though still at compile time), rather than universally. But no great loss either way. I'll trade a bit of performance for the ease of use.