I\'ve added a method to Closure
\'s metaClass
, but I don\'t seem to be able to get a reference for the instance the method is being called on. In th
Explanation:
If you do Closure.metaClass.fixedPoint = ...
then the class Closure will get a new MetaClass, which is ExpandoMetaClass. And in a next step the method is added. Now the default meta class for a Closure is ClosureMetaClass, which neither allows you to add methods, nor does it care about other meta classes much. When you do def f = { Math.round(it / 2.0) }
then you actually create a new class (and instance of it). It extends Closure, but is not Closure itself. And this class will have by default ClosureMetaClass as meta class, totally ignoring what you did with the meta class of Closure.
Solution:
You have to force the usage of ExpandoMetaClass, thus the first line of your code (before f is assigned) should be ExpandoMetaClass.enableGlobally()
:
ExpandoMetaClass.enableGlobally()
Closure.metaClass.fixedPoint = {
while (it != (it = delegate.call(it))) {}
it
}
def f = { Math.round(it / 2.0) }
assert f.fixedPoint(9) == 1
At least for me this code runs without exception...
Side Note:
The Closure stored in the meta class to form the method is usually a clone of what you gave in. The meta class will then set the delegate on the copy. Inspecting the delegate of f by for example println f.@delegate
won't show you the result then.
The problem is that Closure.metaclass
and { -> }.metaClass
are the different instances.
println (Closure.metaClass)
println ({ -> }.metaClass)
yields:
org.codehaus.groovy.runtime.HandleMetaClass@12f5f0d
org.codehaus.groovy.runtime.metaclass.ClosureMetaClass@192d8d6