Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id F1F77200ACC for ; Mon, 2 May 2016 17:29:19 +0200 (CEST) Received: by cust-asf.ponee.io (Postfix) id F0A191609B1; Mon, 2 May 2016 17:29:19 +0200 (CEST) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id EF2F81609A6 for ; Mon, 2 May 2016 17:29:18 +0200 (CEST) Received: (qmail 78369 invoked by uid 500); 2 May 2016 15:29:18 -0000 Mailing-List: contact dev-help@groovy.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@groovy.apache.org Delivered-To: mailing list dev@groovy.apache.org Received: (qmail 78354 invoked by uid 99); 2 May 2016 15:29:17 -0000 Received: from pnap-us-west-generic-nat.apache.org (HELO spamd3-us-west.apache.org) (209.188.14.142) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 02 May 2016 15:29:17 +0000 Received: from localhost (localhost [127.0.0.1]) by spamd3-us-west.apache.org (ASF Mail Server at spamd3-us-west.apache.org) with ESMTP id 1B86A180290 for ; Mon, 2 May 2016 15:29:17 +0000 (UTC) X-Virus-Scanned: Debian amavisd-new at spamd3-us-west.apache.org X-Spam-Flag: NO X-Spam-Score: 1.179 X-Spam-Level: * X-Spam-Status: No, score=1.179 tagged_above=-999 required=6.31 tests=[DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, HTML_MESSAGE=2, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H3=-0.01, RCVD_IN_MSPIKE_WL=-0.01, SPF_PASS=-0.001] autolearn=disabled Authentication-Results: spamd3-us-west.apache.org (amavisd-new); dkim=pass (2048-bit key) header.d=gmail.com Received: from mx1-lw-eu.apache.org ([10.40.0.8]) by localhost (spamd3-us-west.apache.org [10.40.0.10]) (amavisd-new, port 10024) with ESMTP id 3PDxXpf8MAGs for ; Mon, 2 May 2016 15:29:14 +0000 (UTC) Received: from mail-wm0-f45.google.com (mail-wm0-f45.google.com [74.125.82.45]) by mx1-lw-eu.apache.org (ASF Mail Server at mx1-lw-eu.apache.org) with ESMTPS id 907EB5F255 for ; Mon, 2 May 2016 15:29:14 +0000 (UTC) Received: by mail-wm0-f45.google.com with SMTP id a17so148559623wme.0 for ; Mon, 02 May 2016 08:29:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:date:message-id:subject:from:to; bh=YWFYm/XRt7fyOr/gLKvtVpwEVAk4btgLmYSrdsUJfIM=; b=ZbRoH776zbGyaOd5z6qzLVbmIFg2RUZaVTsbpmLMljHb2sGSWFqOg/7L6V5zXM5tTe yO9Y+SdlSpFXMm5IsfLsLyct16DRQZRTrNu5YHu00BIyAHpTZR/NSVes9NzAs74Xc4OQ MSNeSmi3WsXItcAV+7aK0zyEQ4BCrlP08WRNacoz4c4W258W09czLYvOFk/bwctpu1Cr AZfYDfVwfio+sPDHCJbVzoAebcavUi37u7QfsLZ7TmNvxgiqSvJ97HR+rN7K8Ixbr0mS fP4+rdQlWAKUvxfTacjAc8pT8n7+Xr0Ez7AmE2nCALVGwubKNdlgIHyZTHSIw3aYnT5Z Li5g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:in-reply-to:references:date :message-id:subject:from:to; bh=YWFYm/XRt7fyOr/gLKvtVpwEVAk4btgLmYSrdsUJfIM=; b=TdImk47oqsBVnMTmTngFzZeE8WyHBaLcJdMhIbL52JRM64I6aqf5nLaRxV2CmubTBx UDUMR8smGGCSLjcdEdDoIvXZD6/V1VqEcx/lxgOigQWhOTpTcoVLZoi0oRkmcMbj9cwo vlBiWiyMRgLQVlQ8/sWNT4ugJKUPeTTjsIQOah+d5zTLfggUh3tsN1DlST5wYnTx9Ii/ 4jBdLZvs5iF8oJ0vANMt63Ynl5I8QVVs1dTTJAcUqJm2C10eRHyQtpX7PwI59ZjiA78V VBuHlbkzCEw2J3gXVXQ4Qkvy/DBczV8Fr49KQohYFJTFxjPStto/ejkFrzYyz4Os2f1U INSQ== X-Gm-Message-State: AOPr4FUSU5ARFWadolpCyBs9TUi+7jwHge/UDO2KGQfvb/8laHPDPoIiQTm/o6Zw1qYy/h4pwqisIfzl53jdng== MIME-Version: 1.0 X-Received: by 10.194.223.70 with SMTP id qs6mr36622593wjc.119.1462202948445; Mon, 02 May 2016 08:29:08 -0700 (PDT) Received: by 10.194.29.10 with HTTP; Mon, 2 May 2016 08:29:08 -0700 (PDT) In-Reply-To: References: Date: Mon, 2 May 2016 17:29:08 +0200 Message-ID: Subject: Re: Automatic closure coercion and delegate From: Guillaume Laforge To: dev@groovy.apache.org Content-Type: multipart/alternative; boundary=001a11c3b60254ebde0531dda704 archived-at: Mon, 02 May 2016 15:29:20 -0000 --001a11c3b60254ebde0531dda704 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable 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=C3=A9dric Champeau < >> cedric.champeau@gmail.com> wrote: >> >>> Hi guys, >>> >>> I've been grumpy about this for a bit too long to keep it for myself, s= o >>> 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 =3D 'Bob' >>> } >>> >>> Whereas if we had a closure version, a nice and idiomatic way would be >>> to write: >>> >>> configure { >>> name =3D '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 strate= gy >>> 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 so= urce >>> files. Typically, we don't have access to the JDK sources, so we have t= o >>> write: >>> >>> def max =3D['Cedric','Jochen','Guillaume', 'Paul'].stream() >>> .mapToInt { it.length() } >>> .max() >>> .orElse(0) >>> >>> Where with this strategy we could use: >>> >>> def max =3D['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 (wh= ere >>> 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 a= re >>> 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 `Clos= ure` >>> versions. This might be an option for Gradle (even though it would be v= ery >>> 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 objec= ts). >>> 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+ >> >> > > --=20 Guillaume Laforge Apache Groovy committer & PMC Vice-President Product Ninja & Advocate at Restlet Blog: http://glaforge.appspot.com/ Social: @glaforge / Google+ --001a11c3b60254ebde0531dda704 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable

= On Mon, May 2, 2016 at 5:25 PM, Joe Wolf <joewolf@gmail.com>= 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
=C2=A0

-Joe

<= /div>

On Mon, May 2, 2016 at 10:5= 6 AM, Guillaume Laforge <glaforge@gmail.com> wrote:
+1

On Mon, May 2, 2016 at 4:44 PM= , C=C3=A9dric Champeau <cedric.champeau@gmail.com> w= rote:
Hi guys,

<= /div>
I've been grumpy about this for a bit too long to keep it for= myself, so let me explain the issue :)

Imagine yo= u have a Java method that accepts a SAM type:

inte= rface Action<T> {
=C2=A0 =C2=A0void execute(T object)
=
}

class Person {
=C2=A0 =C2=A0 Stri= ng name
}

void configure(Action<Perso= n> config) {=C2=A0
=C2=A0 =C2=A0config.execute(person)
}

then, you can call it in Groovy like this:

configure {
=C2=A0 =C2=A0it.name =3D 'Bob'
}
=

Whereas if we had a closure version, a nice and idiomat= ic way would be to write:

configure {
= =C2=A0 =C2=A0name =3D 'Bob'
}

No= te that in the `Action` version, we have to prefix everything with "it= .".

My wish is to make automatic closure coer= cion automatically set the delegate to the first argument, if available, an= d the delegation strategy to delegate first.

Basic= ally, it is important to integrate with Java 8 style SAM types and still be= nefit 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 =3D['Cedric','Jochen= 9;,'Guillaume', 'Paul'].stream()
=C2=A0 .mapToInt= { it.length() }
=C2=A0 .max()
=C2=A0 .orElse(0)
<= div>=C2=A0=C2=A0
Where with this strategy we could use:

def max =3D['Cedric','Jochen',&#= 39;Guillaume', 'Paul'].stream()
=C2=A0 .mapToInt { le= ngth() }
=C2=A0 .max()
=C2=A0 .orElse(0)
=C2= =A0=C2=A0
Of course, it may look a bit superficial but it i= s super important for nice DSLs like in Gradle. Typically, Gradle has a lot= of domain objects that use the `Action<T>` interface above. Those ac= tions allow the user to configure the domain objects typically from plugins= written in Java (where you cannot use a closure). Since the `Closure` equi= valent 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 o= ne `Closure` method for each `Action` one.

Unfortu= nately, this approach is defeated as soon as you want to use static compila= tion: then, you have no choice but implementing the `Closure` versions. Thi= s 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 co= uld write a code generator that takes all java classes and generates an ext= ension class with closure versions for all, also, but I'd like to know = first what you think of this idea...




<= font color=3D"#888888">--
<= div>
Guillaume LaforgeApache Groovy committer & PMC Vice-President
Pro= duct Ninja & Advocate at Restlet





--
=
=
Guillaume Laforge
Apa= che Groovy committer & PMC Vice-President
Product= Ninja & Advocate at R= estlet

Blog:=C2=A0http://glaforge.appspot.com/
Soci= al: @glaforge= =C2=A0/ Google+
--001a11c3b60254ebde0531dda704--