Is there a way to have callable objects in Groovy? - groovy

If for example I have a class named A. Can I make an object be callable, just like Python does? For example :
def myObject = new A()
myObject()
and that would call some object method. Can it be done?

In Groovy only closures are callable by default. E.g. Classes are not callable out of the box. If necessary you can dynamically add a call method to a type's ExpandoMetaClass to make all instances of that type callable.
Hint: you can try out all code sample using the GroovyConsole
Closures are callable by default in Groovy:
// A closure
def doSomething = { println 'do something'}
doSomething()
// A closure with arguments
def sum = {x, y -> x + y}
sum(5,3)
sum.call(5,3)
// Currying
def sum5 = sum.curry(5)
sum5(3)
To make all instances of a specific type callable you can dynamically add a call method to its meta class:
MyObject.metaClass.call = { prinlnt 'I was called' }
def myObject = new MyObject()
myObject()
If you rather only make a specific instance callable you can dynamically add a call method to its meta class:
def myObject = new MyObject()
myObject.metaClass.call = { println 'Called up on' }
myObject()

Related

Understanding groovy closures

I am trying to understand how the resolution of Groovy's closure is being done in below code,
foo {
a=10
b=20
}
def foo(Closure closure) {
def params = [:]
closure.resolveStrategy = Closure.DELEGATE_FIRST
closure.delegate = params
closure()
println params.a
println params.b
}
In the implementation of foo, the value is never assigned to params, then how come params get the values for a & b
I have read about Groovy closure but couldn't really get as to how this works???
the following line defines property and method resolve strategy for closure DELEGATE_FIRST. that means to get/set/call any property/method it will go to delegate object first and when there is no such property/method it will go to owner object.
closure.resolveStrategy = Closure.DELEGATE_FIRST
and the next line sets delegate object of the closure to params
closure.delegate = params
and finally your closure just sets two properties. and those properties set on delegate object (the param at this moment)
{
a=10
b=20
}

Avoid "Task not serialisable" with nested method in a class

I understand the usual "Task not serializable" issue that arises when accessing a field or a method that is out of scope of a closure.
To fix it, I usually define a local copy of these fields/methods, which avoids the need to serialize the whole class:
class MyClass(val myField: Any) {
def run() = {
val f = sc.textFile("hdfs://xxx.xxx.xxx.xxx/file.csv")
val myField = this.myField
println(f.map( _ + myField ).count)
}
}
Now, if I define a nested function in the run method, it cannot be serialized:
class MyClass() {
def run() = {
val f = sc.textFile("hdfs://xxx.xxx.xxx.xxx/file.csv")
def mapFn(line: String) = line.split(";")
val myField = this.myField
println(f.map( mapFn( _ ) ).count)
}
}
I don't understand since I thought "mapFn" would be in scope...
Even stranger, if I define mapFn to be a val instead of a def, then it works:
class MyClass() {
def run() = {
val f = sc.textFile("hdfs://xxx.xxx.xxx.xxx/file.csv")
val mapFn = (line: String) => line.split(";")
println(f.map( mapFn( _ ) ).count)
}
}
Is this related to the way Scala represents nested functions?
What's the recommended way to deal with this issue ?
Avoid nested functions?
Isn't it working in the way so that in the first case f.map(mapFN(_)) is equivalent to f.map(new Function() { override def apply(...) = mapFN(...) }) and in the second one it is just f.map(mapFN)? When you declare a method with def it is probably just a method in some anonymous class with implicit $outer reference to the enclosing class. But map requires a Function so the compiler needs to wrap it. In the wrapper you just refer to some method of that anonymous class, but not to the instance itself. If you use val, you have a direct reference to the function which you pass to the map. I'm not sure about this, just thinking out loud...

add Closure method to metaClass of groovy class

i knewt how to add method to metaClass of java.util.List :
java.util.List.metaClass.average={
return delegate.sum()/delegate.size();
}
and if i have def myList=[new Person(score:1),new Person(score:2)] , i call to new method as following:
myList.average();
However, i want to call it as following :
myList.average{it.score}
How can i add this method to metaClass to be called as Closure( {} and not ())
You should be able to do:
List.metaClass.average = { Closure c ->
delegate.sum( c ) / delegate.size()
}

How do I dynamically invoke methods in Groovy?

At runtime I'm grabbing a list of method names on a class, and I want to invoke these methods. I understand how to get the first part done from here:
http://docs.codehaus.org/display/GROOVY/JN3535-Reflection
GroovyObject.methods.each{ println it.name }
What I can't seem to find information on is how to then invoke a method once I've grabbed its name.
What I want is to get here:
GroovyObject.methods.each{ GroovyObject.invokeMethod( it.name, argList) }
I can't seem to find the correct syntax. The above seems to assume I've overloaded the default invokeMethod for the GroovyObject class, which is NOT the direction I want to go.
Once you get a MetaMethod object from the metaclass, you can call invoke on it. For example:
class MyClass {
def myField = 'foo'
def myMethod(myArg) { println "$myField $myArg" }
}
test = new MyClass()
test.metaClass.methods.each { method ->
if (method.name == 'myMethod') {
method.invoke(test, 'bar')
}
}
Alternatively, you can use the name directly:
methodName = 'myMethod'
test."$methodName"('bar')
Groovy allows for dynamic method invocation as well as dynamic arguments using the spread operator:
def dynamicArgs = [1,2]
def groovy = new GroovyObject()
GroovyObject.methods.each{
groovy."$it.name"(staticArg, *dynamicArgs)
}
Reference here
Question answered here.

Method overloading in groovy

I am trying to take advantage of the convenience of groovy's scripting syntax to assign properties, but having trouble with a specific case. I must be missing something simple here. I define class A, B, C as so:
class A {
A() {
println "Constructed class A!"
}
}
class B {
B() {
println "Constructed class B!"
}
}
class C {
private member
C() {
println "Constructed class C!"
}
def setMember(A a) {
println "Called setMember(A)!"
member = a
}
def setMember(B b) {
println "Called setMember(B)!"
member = b
}
}
And then try the following calls in a script:
c = new C()
c.setMember(new A()) // works
c.member = new A() // works
c.setMember(new B()) // works
c.member = new B() // doesn't work!
The last assignment results in an error: 'Cannot cast object of class B to class A". Why doesn't it call the proper setMember method for class B like it does for class A?
The shortcut of using the dot notation for calling a property's setter method doesn't do type checking. Instead it seems to use the first entry in the list of methods with a given name and invoke it.
You can also read Pyrasun's extended comments on the shortcomings of Groovy's property handling.
If you want to bypass this (mis)behavior you have to call the setter directly, as Groovy supports type checking for method calls. Alternatively you could also access the field directly without a setter using
c.#member = new B()
or you do the type checking on your own in a single setter method:
def setMember(def param) {
if (param instanceof A) println "Called setMember(A)!"
if (param instanceof B) println "Called setMember(B)!"
member = param
}

Resources