Understanding Groovy - lesson #1

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 !

Comments:

Post a Comment:
Comments are closed for this entry.
About

whacko

Search

Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today