Re: Automatic closure coercion and delegate

2016-05-02 Thread Jochen Theodorou

On 02.05.2016 16:44, Cédric Champeau wrote:
[...]

Of course, it may look a bit superficial but it is super important for
nice DSLs like in Gradle.


could you give an example of a more complex closure usage?

We should be also aware that this change may break code, since it is 
semantic change and a local method of the same name will no longer be 
called if it exists on the delegate. A functional interface is after all 
not something that came really to exist with java8 only, Callable and 
Runnable are examples that existed before and work with Closure already.


Implementation wise to have something like


void configure(Action config) {
config.execute(person)
}


working we need to set the delegate to person, but we don´t know person 
before the method invocation. This means the proxy for the Action 
delegating to the closure config represents must also make the 
delegation setter call.


And there is also the problem of what we do if Action contains default 
methods - I do not consider our current solution as appropriate anymore. 
But of course that is not essential for the idea at hand.



bye Jochen


Re: Automatic closure coercion and delegate

2016-05-02 Thread Guillaume Laforge
On Mon, May 2, 2016 at 5:25 PM, Joe Wolf  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 
> wrote:
>
>> +1
>>
>> On Mon, May 2, 2016 at 4:44 PM, Cédric Champeau <
>> cedric.champ...@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 {
>>>void execute(T object)
>>> }
>>>
>>> class Person {
>>> String name
>>> }
>>>
>>> void configure(Action 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` 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 
>>
>> Blog: http://glaforge.appspot.com/
>> Social: @glaforge  / Google+
>> 
>>
>
>


-- 
Guillaume Laforge
Apache Groovy committer & PMC Vice-President
Product Ninja & Advocate at Restlet 

Blog: http://glaforge.appspot.com/
Social: @glaforge  / Google+



Re: Automatic closure coercion and delegate

2016-05-02 Thread Joe Wolf
+1

Would it be sensible/possible to add a Closure.FIRST_ARGUMENT resolve
strategy and include it in the default resolution chain? The 'it'-less
closure would behave as expected even without pre-assigning the delegate
(provided that length() was not defined by the delegate/owner). It'd still
probably be a good idea to automatically set the delegate anyways...just
throwing out some thoughts.

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

-Joe


On Mon, May 2, 2016 at 10:56 AM, Guillaume Laforge 
wrote:

> +1
>
> On Mon, May 2, 2016 at 4:44 PM, Cédric Champeau  > 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 {
>>void execute(T object)
>> }
>>
>> class Person {
>> String name
>> }
>>
>> void configure(Action 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` 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 
>
> Blog: http://glaforge.appspot.com/
> Social: @glaforge  / Google+
> 
>


Automatic closure coercion and delegate

2016-05-02 Thread Cédric Champeau
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 {
   void execute(T object)
}

class Person {
String name
}

void configure(Action 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` 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...