Agreed. I almost forgot about the special arity case of defining a closure as { /* do something */ } as it can be called with either 0 or 1 arguments, where as { -> } accepts no arguments and { x -> } takes exactly one argument.
Would it a a good compromise to support plain typed arguments out of the box, that is { String arg0, int arg1 -> } vs { arg0, arg1 -> } ? 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. On Wed, Jan 18, 2017 at 1:52 PM, Jochen Theodorou <blackd...@gmx.org> wrote: > > > 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 > > >