FatalError
FatalError

Reputation: 54541

Why does a method closure on a Class object fail?

In groovy it's pretty easy to create a method closure, for example:

groovy:000> p = 1.&plus
===> org.codehaus.groovy.runtime.MethodClosure@a7981d5
groovy:000> p(3)
===> 4

However, for some reason it fails when trying to use an instance of Class:

groovy:000> List.isInstance([])
===> true
groovy:000> t = List.&isInstance
===> org.codehaus.groovy.runtime.MethodClosure@31ca1a68
groovy:000> t([])
ERROR groovy.lang.MissingMethodException:
No signature of method: java.util.List.isInstance() is applicable for argument types: (java.util.ArrayList) values: [[]]
        at groovysh_evaluate.run (groovysh_evaluate:2)
        ...
groovy:000> t = List.class.&isInstance
===> org.codehaus.groovy.runtime.MethodClosure@7b34c5ff
groovy:000> t([])
ERROR groovy.lang.MissingMethodException:
No signature of method: java.util.List.isInstance() is applicable for argument types: (java.util.ArrayList) values: [[]]
        at groovysh_evaluate.run (groovysh_evaluate:2)
        ...

It's pretty easy to work around this, but I'd like to understand why this happens. Is there something in the MOP that stops this from working, etc?

Upvotes: 4

Views: 1230

Answers (1)

dmahapatro
dmahapatro

Reputation: 50245

When you use a method pointer on instance of Class then it has to explicitly use the doCall() method provided by MethodClosure instead of using the default call() of Closure.

doCall method from MethodClosure overrides Closure's doCall and intercepts the method call by using invokeMethod instead of calling call() from Closure.

The MethodClosure will also work if you explicitly use the InvokerHelper which is synonymous to doCall in MethodClosure or simply metaClass List.

import org.codehaus.groovy.runtime.InvokerHelper

t = List.&isInstance

assert t.owner.simpleName == 'List'
assert t.doCall([]) == true    
assert InvokerHelper.getMetaClass(t.owner).
              invokeStaticMethod(t.owner, 'isInstance', []) == true
assert List.metaClass.invokeStaticMethod(t.owner, 'isInstance', []) == true

invokeStaticMethod of MOP is used if the object is an instance of Class.

On the other hand, &plus works appropriately because method pointer is created on a POJO.

Upvotes: 3

Related Questions