Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

On closures and groovy builder pattern

Tags:

groovy

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?

like image 308
kaneda Avatar asked Apr 28 '26 08:04

kaneda


1 Answers

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;
}
like image 103
Will Avatar answered Apr 30 '26 16:04

Will