Re: Automatic closure coercion and delegate

2016-05-23 Thread Graeme Rocher
+1 this seems like a great idea.

Graeme
On Wed, May 18, 2016 at 9:11 AM, Jochen Theodorou  wrote:
On 18.05.2016 08:46, Peter Ledbrook wrote:
> I'm not even sure there's a right answer to this. I guess I would expect
> local variables defined outside of the closure to be accessible within
> it. Would that work with DELEGATE_ONLY?

yes, static scoping is done by the compiler, before any runtime can
fiddle around with redirected calls using the delegation strategy

bye Jochen

Re: Automatic closure coercion and delegate

2016-05-03 Thread Mario Garcia
+1

2016-05-03 10:29 GMT+02:00 Jochen Theodorou :

> On 03.05.2016 08:26, Cédric Champeau wrote:
> [...]
>
>> repositories { // Action> maven { Action
>>  url ''
>> }
>> }
>>
>
> I see... I would feel much better if this was done by a special interface,
> coming from Groovy... maybe even a trait. But I guess this is not really an
> option.
>
> [...]
>
> Doing the same for abstract classes should be straightforward. For
>> static compilation, it's going to be more complicated and probably
>> requires transparently invoking a configurer (like Gradle does).
>>
>
> the proxy generation will work the same, I guess you are talking about the
> direct method calls inside the closure as well es letting it pass static
> compilation. But I still don't understand what you mean by configurer
>
> bye Jochen
>
>
>


Re: Automatic closure coercion and delegate

2016-05-03 Thread Jochen Theodorou

On 03.05.2016 08:26, Cédric Champeau wrote:
[...]

repositories { // Action
 url ''
}
}


I see... I would feel much better if this was done by a special 
interface, coming from Groovy... maybe even a trait. But I guess this is 
not really an option.


[...]


Doing the same for abstract classes should be straightforward. For
static compilation, it's going to be more complicated and probably
requires transparently invoking a configurer (like Gradle does).


the proxy generation will work the same, I guess you are talking about 
the direct method calls inside the closure as well es letting it pass 
static compilation. But I still don't understand what you mean by configurer


bye Jochen




Re: Automatic closure coercion and delegate

2016-05-03 Thread Cédric Champeau
2016-05-02 18:11 GMT+02:00 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?
>

Sure, basically you can have that kind of configuration:

dependencies {
   compile '...'
}

(the method is dependencies(Action, and we
generate a Closure version at runtime) or:

repositories { // Action
url ''
   }
}


> 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.
>
>
I have a patch that does the work for functional interfaces already:

public static Object coerceToSAM(Closure argument, Method method,
Class clazz, boolean isInterface) {
if (argument!=null && clazz.isAssignableFrom(argument.getClass())) {
return argument;
}
if (isInterface) {
if (Traits.isTrait(clazz)) {
Map impl = Collections.singletonMap(
method.getName(),
argument
);
return
ProxyGenerator.INSTANCE.instantiateAggregate(impl,Collections.singletonList(clazz));
}
return Proxy.newProxyInstance(
clazz.getClassLoader(),
new Class[]{clazz},
new SAMClosure(argument));
} else {
Map m = new HashMap();
m.put(method.getName(), argument);
return ProxyGenerator.INSTANCE.
instantiateAggregateFromBaseClass(m, clazz);
}
}

private static class SAMClosure extends ConvertedClosure {
public SAMClosure(final Closure closure) {
super(closure);
}

@Override
public Object invokeCustom(final Object proxy, final Method
method, final Object[] args) throws Throwable {
if (args!=null && args.length>0) {
Closure delegate = (Closure) getDelegate();
delegate.setResolveStrategy(Closure.DELEGATE_FIRST);
delegate.setDelegate(args[0]);
}
return super.invokeCustom(proxy, method, args);
}
}


Doing the same for abstract classes should be straightforward. For static
compilation, it's going to be more complicated and probably requires
transparently invoking a configurer (like Gradle does).

>
> bye Jochen
>


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...