Groovy 2 and Closure on the API.

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

Groovy 2 and Closure on the API.

Luke Daley-2
Hi,

Since we are now considering Groovy 2 for Gradle 2, I wanted to throw
this into the conversation…

One of the great additions to Groovy 2.2 was implicit closure coercion
for Single Abstract Method types. In 2.3 this gets better with closure
param type inference. This means you can do the following…

   // Setup…

   interface Action<T> {
     void execute(T thing)
   }

   class Thing {
     String name
   }

   class ThingConfigurer {
     Thing thing
     void conf(Action<Thing> action) {
         action.execute(thing)
     }
   }

   def t = new Thing()
   def tc = new ThingConfigurer(thing: t)

   // The point…

   tc.conf {
       it.name = "foo"
   }

   assert t.name == "foo"



That is, closures are implicitly converted to types. This works if the
SAM has a return type and even for multiple params (and generics are
inferred).

This would be great for us because it means we don't have to generate
overloads at runtime and IDEA at least understands these closure
coercion rules really well where as it does not understand our runtime
overloads. I say “would” because it doesn't quite match our pattern of
making the param the delegate in the Action case.

I think we can still get some benefit out of this for other cases (e.g.
Test#beforeTest), but I can't find any way to leverage this and avoid
our runtime generated overloads because of the delegate issue. It's a shame.

The end result, is that we could potentially drop Closure from our API
completely for Gradle 2 without forcing users to change their
buildscripts. In the Closure usages that aren't actually used for
configure-by-closure (e.g. Test#beforeTest) would could replace with
real types.



---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email


Reply | Threaded
Open this post in threaded view
|

Re: Groovy 2 and Closure on the API.

Adam Murdoch

On 28 Feb 2014, at 11:58 am, Luke Daley <[hidden email]> wrote:

Hi,

Since we are now considering Groovy 2 for Gradle 2, I wanted to throw this into the conversation…

One of the great additions to Groovy 2.2 was implicit closure coercion for Single Abstract Method types. In 2.3 this gets better with closure param type inference. This means you can do the following…

 // Setup…

 interface Action<T> {
   void execute(T thing)
 }

 class Thing {
   String name
 }

 class ThingConfigurer {
   Thing thing
   void conf(Action<Thing> action) {
       action.execute(thing)
   }
 }

 def t = new Thing()
 def tc = new ThingConfigurer(thing: t)

 // The point…

 tc.conf {
     it.name = "foo"
 }

 assert t.name == "foo"



That is, closures are implicitly converted to types. This works if the SAM has a return type and even for multiple params (and generics are inferred).

This would be great for us because it means we don't have to generate overloads at runtime and IDEA at least understands these closure coercion rules really well where as it does not understand our runtime overloads. I say “would” because it doesn't quite match our pattern of making the param the delegate in the Action case.

I think we can still get some benefit out of this for other cases (e.g. Test#beforeTest), but I can't find any way to leverage this and avoid our runtime generated overloads because of the delegate issue. It's a shame.

The end result, is that we could potentially drop Closure from our API completely for Gradle 2 without forcing users to change their buildscripts. In the Closure usages that aren't actually used for configure-by-closure (e.g. Test#beforeTest) would could replace with real types.

It’s not just build scripts that use the API, it’s also compiled plugins implemented in Java. Does the coercion also work for compiled plugins implemented in Groovy 1.8 running under Groovy 2?

Let’s just use the regular deprecate-then-remove approach to remove these methods. They don’t cause us much pain. We do want to get rid of them, however.


--
Adam Murdoch
Gradle Co-founder
http://www.gradle.org
VP of Engineering, Gradleware Inc. - Gradle Training, Support, Consulting
http://www.gradleware.com



Reply | Threaded
Open this post in threaded view
|

Re: Groovy 2 and Closure on the API.

Luke Daley-2


On 27 Feb 2014, at 17:50, Adam Murdoch <[hidden email]> wrote:


On 28 Feb 2014, at 11:58 am, Luke Daley <[hidden email]> wrote:

Hi,

Since we are now considering Groovy 2 for Gradle 2, I wanted to throw this into the conversation…

One of the great additions to Groovy 2.2 was implicit closure coercion for Single Abstract Method types. In 2.3 this gets better with closure param type inference. This means you can do the following…

 // Setup…

 interface Action<T> {
   void execute(T thing)
 }

 class Thing {
   String name
 }

 class ThingConfigurer {
   Thing thing
   void conf(Action<Thing> action) {
       action.execute(thing)
   }
 }

 def t = new Thing()
 def tc = new ThingConfigurer(thing: t)

 // The point…

 tc.conf {
     it.name = "foo"
 }

 assert t.name == "foo"



That is, closures are implicitly converted to types. This works if the SAM has a return type and even for multiple params (and generics are inferred).

This would be great for us because it means we don't have to generate overloads at runtime and IDEA at least understands these closure coercion rules really well where as it does not understand our runtime overloads. I say “would” because it doesn't quite match our pattern of making the param the delegate in the Action case.

I think we can still get some benefit out of this for other cases (e.g. Test#beforeTest), but I can't find any way to leverage this and avoid our runtime generated overloads because of the delegate issue. It's a shame.

The end result, is that we could potentially drop Closure from our API completely for Gradle 2 without forcing users to change their buildscripts. In the Closure usages that aren't actually used for configure-by-closure (e.g. Test#beforeTest) would could replace with real types.

It’s not just build scripts that use the API, it’s also compiled plugins implemented in Java. Does the coercion also work for compiled plugins implemented in Groovy 1.8 running under Groovy 2?

Yes. The coercion is at runtime.

Let’s just use the regular deprecate-then-remove approach to remove these methods. They don’t cause us much pain. We do want to get rid of them, however.

It means it's harder to enforce Groovy not creeping into the public API because it means we have to joint compile the API.

Now I think about this though, we leak more than just Closure so it's a non starter regardless.



--
Adam Murdoch
Gradle Co-founder
http://www.gradle.org
VP of Engineering, Gradleware Inc. - Gradle Training, Support, Consulting
http://www.gradleware.com



Reply | Threaded
Open this post in threaded view
|

Re: Groovy 2 and Closure on the API.

Adam Murdoch

On 28 Feb 2014, at 4:56 pm, Luke Daley <[hidden email]> wrote:



On 27 Feb 2014, at 17:50, Adam Murdoch <[hidden email]> wrote:


On 28 Feb 2014, at 11:58 am, Luke Daley <[hidden email]> wrote:

Hi,

Since we are now considering Groovy 2 for Gradle 2, I wanted to throw this into the conversation…

One of the great additions to Groovy 2.2 was implicit closure coercion for Single Abstract Method types. In 2.3 this gets better with closure param type inference. This means you can do the following…

 // Setup…

 interface Action<T> {
   void execute(T thing)
 }

 class Thing {
   String name
 }

 class ThingConfigurer {
   Thing thing
   void conf(Action<Thing> action) {
       action.execute(thing)
   }
 }

 def t = new Thing()
 def tc = new ThingConfigurer(thing: t)

 // The point…

 tc.conf {
     it.name = "foo"
 }

 assert t.name == "foo"



That is, closures are implicitly converted to types. This works if the SAM has a return type and even for multiple params (and generics are inferred).

This would be great for us because it means we don't have to generate overloads at runtime and IDEA at least understands these closure coercion rules really well where as it does not understand our runtime overloads. I say “would” because it doesn't quite match our pattern of making the param the delegate in the Action case.

I think we can still get some benefit out of this for other cases (e.g. Test#beforeTest), but I can't find any way to leverage this and avoid our runtime generated overloads because of the delegate issue. It's a shame.

The end result, is that we could potentially drop Closure from our API completely for Gradle 2 without forcing users to change their buildscripts. In the Closure usages that aren't actually used for configure-by-closure (e.g. Test#beforeTest) would could replace with real types.

It’s not just build scripts that use the API, it’s also compiled plugins implemented in Java. Does the coercion also work for compiled plugins implemented in Groovy 1.8 running under Groovy 2?

Yes. The coercion is at runtime.

Let’s just use the regular deprecate-then-remove approach to remove these methods. They don’t cause us much pain. We do want to get rid of them, however.

It means it's harder to enforce Groovy not creeping into the public API because it means we have to joint compile the API.

Now I think about this though, we leak more than just Closure so it's a non starter regardless.

So far, we use code reviews to stop the leakage, but we could automate this. It would be worth doing this to also check that we aren’t breaking backwards compatibility, and that new things are @Incubating when added (as as a default).


--
Adam Murdoch
Gradle Co-founder
http://www.gradle.org
VP of Engineering, Gradleware Inc. - Gradle Training, Support, Consulting
http://www.gradleware.com