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