+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 <glafo...@gmail.com> 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<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> >