groovy-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Jochen Theodorou <blackd...@gmx.org>
Subject Re: SAM type closure coercion
Date Wed, 18 Jan 2017 12:52:14 GMT


On 18.01.2017 12:33, Remi Forax wrote:
> 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

What Groovy currently does is look if the parameter type is a SAM type 
and then mark this as a potential match with conversion. It does not 
take arity into account, neither generics, nor the returntype of the 
"lambda".

arity is a problem. {1} is a Groovy Closure with what arity? This can 
take one optional argument. {->1} is clear to take none and {x->1} is 
clear to take one argument. If we say you can use the shorter style, but 
then you may get into trouble, this is fine.

Then there is of course not only the arity, but also the types of the 
parameters. {x->1} is an object taking Closure in Groovy. This is 
different from lambdas where the type of x may be defined by the SAM 
type we match against. So for example if I have foo(x->1+x>10) and there 
is a Predicate<String> as well as a Function<Integer,Boolean>, then of 
course the Function is supposed to be taken, but javac can try to first 
match against Predicate and if that does not work try to match against 
Function. It can see that for Integer, there is a plus method through 
unboxing, thus Function can work and if there are no further candidates 
the method selection is unambiguous, thus can be completed and no 
compilation error will happen. In dynamic Groovy we only see x of type 
Object. If there is a plus method is decided at runtime. But as such we 
cannot decide between the Predicate and the Function. Which means the 
Closure in the will have to be typed by you.

And then of course we could get generics into the game.

> class X<T> {
>   def foo(Function<T,Boolean> f) {..}
>   def foo(Predicate<T> f) {..}
> }
>
> def x = new X<MyType>()
> x.foo {Integer x-> x+1>0}

Now for which values of MyType is this a legal call? at runtime we do 
not even have the information that x is a X<MyType>. Since we do not 
have that information, we cannot know what the T in the declaration of X 
means. So even though we used a type for x, we can still not decide here!

And then there is the problem of the return type. What is the type of 
x+1 in dynamic Groovy? We actually do not know. For x+1>0 we can infer 
that it must be boolean, because of using compareTo and that only 
returns a boolean and is enforced. But for arbitrary expressions we 
simply do not have the information before the result object is there and 
that is too late for the method selection of the method that will most 
likely do the invocation in the first place (or the invocation may never 
happen).

So yes, we can improve here. But there are heavy limits for this static 
compilation controlled logic in dynamic Groovy.

bye Jochen



Mime
View raw message