Since, I've been briefly looking at groovy, I decided to read up on one of the much talked about
features - closures. Looking at the documentation
here
on Groovy site, the example (excerpts below) did not fully make sense to me.
public class GVector extends java.util.Vector {
public void apply( c ){
for (i in 0..<size()){
this[i] = c(this[i])
}
}
}
...
def gVect = new GVector()
gVect.add(2)
...
def c = { numberToSquare -> numberToSquare * numberToSquare }
gVect.apply(c) // the elements in the GVector have all been squared.
The expression 'this[i]' is the one that I did not quite understand - how exactly did this[i] result in the calling get and set on the java.util.Vector
So, dug a little deeper at got at the 'Operator Overloading' section. Well, it defines the relevant overloaded functions as
a[b] a.getAt(b)
a[b] = c a.putAt(b, c)
A quick glance at the java.util.Vector and there exists no 'getAt' method. A few google searches did not reveal anything meaningful.
javap of the groovy classes did not help.
Hmmm ...
This is what I decided to do - the oldest java trick in my book when I have access to the source and it seldom fails me.
Modify the GVector class by defining a get method:
public Object get(int index) {
Thread.dumpStack(); // my favourite debugging tool
return super.get(index);
}
And it all made sense. DefaultGroovyMethods (a humungous class) defined
here holds the the key. This class seems to be a doing a lot of behind the scenes groovy(the-dynamic-language)magic. The magic doesn't really sink in till you've understood the inner working of a few of them. Revelant sections of the stacktrace
java.lang.Exception: Stack trace
at java.lang.Thread.dumpStack(Thread.java:1158)
...
at GVector.get(TestClosure.groovy:9)
at org.codehaus.groovy.runtime.DefaultGroovyMethods.getAt(DefaultGroovyMethods.java:2034)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at org.codehaus.groovy.runtime.ReflectionMetaMethod.invoke(ReflectionMetaMethod.java:69)
at org.codehaus.groovy.runtime.NewInstanceMetaMethod.invoke(NewInstanceMetaMethod.java:109)
at org.codehaus.groovy.runtime.MetaClassHelper.doMethodInvoke(MetaClassHelper.java:713)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:560)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:450)
at org.codehaus.groovy.runtime.Invoker.invokeMethod(Invoker.java:131)
at org.codehaus.groovy.runtime.InvokerHelper.invokeMethod(InvokerHelper.java:111)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodN(ScriptBytecodeAdapter.java:187)
at GVector.apply(TestClosure.groovy:4)
...
Also, further on in the example, the following statement is called
gVect.apply{ value -> println(value) }
Hmmm, would this not mutate the state of the object ? Well it should, but wasn't entirely sure.
So, this helped
def gVect = new GVector()
gVect.add(1)
gVect.add(2)
gVect.add(3)
def c = { numberToSquare -> numberToSquare * numberToSquare }
gVect.apply(c)
gVect.apply{ value -> println(value) }
gVect.apply{ value -> println(value) } // AGAIN
Runtime output for the above code:
1
4
9
null
null
null
The 'return value' from a closure is formally defined in the
Closure document under
the heading 'Closure Return Value'. Essentially a closure ALWAYS has a return value. No points on guessing what a void maps to.
All in all, closures are a very powerful concept and there are
proposals to introduce them in the Java language !
JRuby 0.9.8 is out and so is rails-integration 1.0. Rails 1.2.x has been out for a couple of months
and there's a new release of ActiveRecord-JDBC 0.2.3. The good news is that
JRuby 0.9.8 is
lot more Rails compatible
than ever before.
For
GlassFish users this means:
-
For RoR deployed as a WAR - only the shared mode works. Therefore, instead of running that
standalone rake task
you should run 'rake war:shared:create'. You need to have the JRUBY_HOME enviroment variable set
and a jruby/rails installation.
-
For RoR deployed directly on Grizzly, things seem to have regressed. Hopefully, we'll get the fixes real soon but there are workarounds and if you're interested email me at ashish dot sahni at sun dot com
Stay tuned ...
I think so.
This debate about language preferences can get religious and being an atheist I know how that goes

That's not so to say that
Groovy is the only
religion language that should exist. Horses for courses, right ? But, I think
Groovy is good. How good ? Well - really good. Off the cuff in no particular order here's why:
-
Groovy code compile to Java bytecodes - Java tool support, Java Security, Java EE ...
-
Syntax is simple - code more maintainable
-
MOP (Meta Object Protocol) - enables some wicked maneuvers
-
In-built XML support - unbelievable how simple it is to read/write XML
-
Groovy has Grails !
-
... and more. You can find the entire feature set on the Groovy site.
Currently only Rhino, a JavaScript interpreter, is bundled with Java SE 6. The Java platform is capable of integrating with any script engine conforming to JSR 223, and it can't possible bundle ?-too-many scripting engines out of the box, but
Groovy and (the language) Java seem to be a perfect fit.
Is the
Groovy gravy spicy enough for Java's palate ? I hope so ...