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