groovy-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Guillaume Laforge <glafo...@gmail.com>
Subject Re: Automatic closure coercion and delegate
Date Mon, 02 May 2016 15:29:08 GMT
On Mon, May 2, 2016 at 5:25 PM, Joe Wolf <joewolf@gmail.com> wrote:

> [...]
>
> [Hi, all. This is my first post to the list--been a happy Groovy user
> since version 1.5]
>

Welcome here and thanks for using Groovy since 1.5!!! :-)

Guillaume


>
> -Joe
>
>
> On Mon, May 2, 2016 at 10:56 AM, Guillaume Laforge <glaforge@gmail.com>
> wrote:
>
>> +1
>>
>> On Mon, May 2, 2016 at 4:44 PM, C├ędric Champeau <
>> cedric.champeau@gmail.com> wrote:
>>
>>> Hi guys,
>>>
>>> I've been grumpy about this for a bit too long to keep it for myself, so
>>> let me explain the issue :)
>>>
>>> Imagine you have a Java method that accepts a SAM type:
>>>
>>> interface Action<T> {
>>>    void execute(T object)
>>> }
>>>
>>> class Person {
>>>     String name
>>> }
>>>
>>> void configure(Action<Person> config) {
>>>    config.execute(person)
>>> }
>>>
>>> then, you can call it in Groovy like this:
>>>
>>> configure {
>>>    it.name = 'Bob'
>>> }
>>>
>>> Whereas if we had a closure version, a nice and idiomatic way would be
>>> to write:
>>>
>>> configure {
>>>    name = 'Bob'
>>> }
>>>
>>> Note that in the `Action` version, we have to prefix everything with
>>> "it.".
>>>
>>> My wish is to make automatic closure coercion automatically set the
>>> delegate to the first argument, if available, and the delegation strategy
>>> to delegate first.
>>>
>>> Basically, it is important to integrate with Java 8 style SAM types and
>>> still benefit from a nicer Groovy DSL _without_ having to change the source
>>> files. Typically, we don't have access to the JDK sources, so we have to
>>> write:
>>>
>>> def max =['Cedric','Jochen','Guillaume', 'Paul'].stream()
>>>   .mapToInt { it.length() }
>>>   .max()
>>>   .orElse(0)
>>>
>>> Where with this strategy we could use:
>>>
>>> def max =['Cedric','Jochen','Guillaume', 'Paul'].stream()
>>>   .mapToInt { length() }
>>>   .max()
>>>   .orElse(0)
>>>
>>> Of course, it may look a bit superficial but it is super important for
>>> nice DSLs like in Gradle. Typically, Gradle has a lot of domain objects
>>> that use the `Action<T>` interface above. Those actions allow the user
to
>>> configure the domain objects typically from plugins written in Java (where
>>> you cannot use a closure). Since the `Closure` equivalent methods are
>>> always the same and that it's super simple to forget to implement one,
>>> Gradle chose to _not_ implement the `Closure` versions. Instead, they are
>>> generated at runtime, so the objects are decorated with one `Closure`
>>> method for each `Action` one.
>>>
>>> Unfortunately, this approach is defeated as soon as you want to use
>>> static compilation: then, you have no choice but implementing the `Closure`
>>> versions. This might be an option for Gradle (even though it would be very
>>> tedious), but not for all cases (we could also do this using extension
>>> methods, though, but really, you'd be doing this for _all_ domain objects).
>>> I think I could write a code generator that takes all java classes and
>>> generates an extension class with closure versions for all, also, but I'd
>>> like to know first what you think of this idea...
>>>
>>>
>>
>>
>> --
>> Guillaume Laforge
>> Apache Groovy committer & PMC Vice-President
>> Product Ninja & Advocate at Restlet <http://restlet.com>
>>
>> Blog: http://glaforge.appspot.com/
>> Social: @glaforge <http://twitter.com/glaforge> / Google+
>> <https://plus.google.com/u/0/114130972232398734985/posts>
>>
>
>


-- 
Guillaume Laforge
Apache Groovy committer & PMC Vice-President
Product Ninja & Advocate at Restlet <http://restlet.com>

Blog: http://glaforge.appspot.com/
Social: @glaforge <http://twitter.com/glaforge> / Google+
<https://plus.google.com/u/0/114130972232398734985/posts>

Mime
View raw message