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 !