Starting to grasp closures in general and some groovy features.
Given the following code:
class Mailer {
void to(final String to) { println "to $to" }
void from(final String from) { println "from $from" }
static void send(Closure configuration) {
Mailer mailer = new Mailer()
mailer.with configuration
}
}
class MailSender {
static void sendMessage() {
Mailer.send {
to 'them'
from 'me'
}
}
}
MailSender.sendMessage()
What happens under the hood when you pass a closure to Mailer.send method?
Does to and from are passed as arguments from the Closure point of view? Which types the Closure maps them?
And then inside the Mailer.send method at the moment the Mailer object calls mailer.with receiving the configuration object, the object maps them into method calls. Groovy does this by reflection?
Groovy can dynamically define the delegate of a closure and even the this object.
with is setting the delegate and executing the closure. This is a verbose way to achieve the same:
def math = {
given 4
sum 5
print
}
class PrintMath {
def initial
def given(val) {
initial = val
}
def sum(val) {
initial += val
}
def getPrint() {
println initial
return initial
}
}
math.delegate = new PrintMath()
math.resolveStrategy = Closure.DELEGATE_ONLY
assert math() == 9
What happens under the hood when you pass a closure to Mailer.send method?
It receives a not-yet-executed block of code.
Does to and from are passed as arguments from the Closure point of view?
No, it is better thinking of them as an anonymous class/lambda in java, or a function(){} in javascript.
Which types the Closure maps them?
None, they are method calls waiting to be executed. They can be delegated to different objects, though.
And then inside the Mailer.send method at the moment the Mailer object calls mailer.with receiving the configuration object, the object maps them into method calls. Groovy does this by reflection?
You can decompile a Groovy class file to see what is going on. IIRC, Groovy currently uses a "reflector" strategy (with an arrayOfCallSite caching) to make calls faster OR it can use invokedynamic.
The closure math in the code above will result in this class:
// .. a lot of techno-babble
public Object doCall(Object it) {
CallSite[] arrayOfCallSite = $getCallSiteArray();
arrayOfCallSite[0].callCurrent(this, Integer.valueOf(4));
arrayOfCallSite[1].callCurrent(this, Integer.valueOf(5));
return arrayOfCallSite[2].callGroovyObjectGetProperty(this);
return null;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With