groovy-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Remi Forax <fo...@univ-mlv.fr>
Subject Re: SAM type closure coercion
Date Wed, 18 Jan 2017 11:33:51 GMT
I agree with Jesper, 
solving all the cases is an uncanny valley. 

The JEP 302 [1] has a good introduction on what javac does or not in case of overloading 
(and what currently does not work but is expected to work with java 10). 

Also the warning proposed by Jesper exists in javac under the name 'overloads'. 

cheers, 
Rémi 

[1] http://openjdk.java.net/jeps/302 

> De: "Jesper Steen Møller" <jesper@selskabet.org>
> À: dev@groovy.apache.org
> Envoyé: Mercredi 18 Janvier 2017 12:20:05
> Objet: Re: SAM type closure coercion

> A word of warning: Solving this according to the spec is a hard problem
> (speaking from experience with the Eclipse compiler when supporting Java 8),
> especially if you add parameterized types to the equation. To quote the JLS:
> "In JSR 335, the greatest complexity lurked in the interaction of implicitly
> typed lambda expressions with overload resolution.”

> Checking the arity of the closure will likely fix many problems, but some of the
> really tricky ones (involving specificity rules) could take weeks.

> Couldn’t we add a warning if we detect an overloaded method being called with a
> closure as an argument?

> -Jesper

>> On 18 Jan 2017, at 12.04, Cédric Champeau < cedric.champeau@gmail.com > wrote:

>> This is something that we can improve. We knew it when we implemented SAM type
>> coercion, and decided to wait until someone complains, to see how often this
>> use case happens :)

>> 2017-01-18 11:59 GMT+01:00 Andres Almiray < aalmiray@gmail.com > :

>>> Hello everyone,

>>> Just yesterday Greg L. Turnquist blogged about an usage pattern of Spinnaker,
>>> Cloud Foundry, and Groovy. See
>>> http://greglturnquist.com/2017/01/reactively-talking-to-cloud-foundry-with-groovy.html

>>> Basically he complains that Groovy can't coerce a Closure to a given SAM type.
>>> In his own words

>>> "Groovy has this nice feature where it can coerce objects. However, with all
the
>>> overloading, Groovy gets lost and can’t tell which TupleUtils function to
>>> target."

>>> Now I know that based on historical reasons Groovy did not coerce closures into
>>> SAMs until very "recently" (was it 2.2?). We also gained @DelegatesTo in order
>>> to supply additional hints to the compiler (@CompileStatic and @TypeChecked)
>>> and IDEs. Despite all this Groovy does not offer a "clean" solution to
>>> automatically coerce a closure into a SAM.

>>> Take for example the following Java code:

>>> ----
>>> public interface Function1 { void call(String arg0); }

>>> public interface Function2 { void call(String arg0, String arg1); }

>>> import groovy.lang.DelegatesTo;
>>> public class API {
>>> public void doit(@DelegatesTo Function1 func) {
>>> System.out.println("Invoking "+ func.toString());
>>> func.call("arg0");
>>> }

>>> public void doit(@DelegatesTo Function2 func) {
>>> System.out.println("Invoking "+ func.toString());
>>> func.call("arg0", "arg1");
>>> }
>>> }
>>> -----

>>> Invoking an instance of API from Groovy

>>> ----
>>> class Main {
>>> static void main(String[] args) {
>>> API api = new API()
>>> api.doit({ String arg0 -> println "Received $arg0" })
>>> api.doit({ String arg0, String arg1 -> println "Received $arg0 $arg1" })
>>> }
>>> }
>>> ----

>>> Results in a runtime exception such as

>>> Exception in thread "main" groovy.lang.GroovyRuntimeException: Ambiguous method
>>> overloading for method sample.API#doit.
>>> Cannot resolve which method to invoke for [class sample.Main$_main_closure1]
due
>>> to overlapping prototypes between:
>>> [interface sample.Function1]
>>> [interface sample.Function2]
>>> at groovy.lang.MetaClassImpl.chooseMostSpecificParams(MetaClassImpl.java:3263)
>>> at groovy.lang.MetaClassImpl.chooseMethodInternal(MetaClassImpl.java:3216)
>>> at groovy.lang.MetaClassImpl.chooseMethod(MetaClassImpl.java:3159)
>>> at
>>> groovy.lang.MetaClassImpl.getMethodWithCachingInternal(MetaClassImpl.java:1336)
>>> at groovy.lang.MetaClassImpl.createPojoCallSite(MetaClassImpl.java:3391)
>>> at
>>> org.codehaus.groovy.runtime.callsite.CallSiteArray.createPojoSite(CallSiteArray.java:132)
>>> at
>>> org.codehaus.groovy.runtime.callsite.CallSiteArray.createCallSite(CallSiteArray.java:166)
>>> at
>>> org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
>>> at
>>> org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
>>> at
>>> org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
>>> at sample.Main.main(Main.groovy:6)

>>> Activating static type checking yields

>>> /private/tmp/foo/src/main/groovy/sample/Main.groovy: 7: [Static type checking]
-
>>> Reference to method is ambiguous. Cannot choose between [void
>>> sample.API#doit(sample.Function1), void sample.API#doit(sample.Function2)]
>>> @ line 7, column 9.
>>> api.doit({ String arg0 -> println "Received $arg0" })
>>> ^

>>> /private/tmp/foo/src/main/groovy/sample/Main.groovy: 8: [Static type checking]
-
>>> Reference to method is ambiguous. Cannot choose between [void
>>> sample.API#doit(sample.Function1), void sample.API#doit(sample.Function2)]
>>> @ line 8, column 9.
>>> api.doit({ String arg0, String arg1 -> println "Received $arg0 $arg1" })

>>> Clearly Groovy requires some hints to determine the first closure must be
>>> coerced to Function1 and the second to Function2. Not even @DelegatesTo helps
>>> in this case.

>>> The current "workaround" (from a Java dev POV anyway) is to sprinkle the code
>>> with usages of the 'as' keyword to explicitly coerce a closure into a target
>>> type. And this is exactly where the Java interop history breaks due to Java 8,
>>> because as we know Java 8 lambda expressions are automatically coerced into a
>>> matching SAM type.

>>> Does the parrot parser offer an alternative to this problem?

>>> Can the compiler be aware of additional arg/type information provided by the
>>> Closure to figure out the right SAM type to use?

>>> Cheers,
>>> Andres

>>> -------------------------------------------
>>> Java Champion; Groovy Enthusiast
>>> http://jroller.com/aalmiray
>>> http://www.linkedin.com/in/aalmiray
>>> --
>>> What goes up, must come down. Ask any system administrator.
>>> There are 10 types of people in the world: Those who understand binary, and
>>> those who don't.
>>> To understand recursion, we must first understand recursion.

Mime
View raw message