From forax at univ-mlv.fr Fri Nov 2 09:48:55 2012 From: forax at univ-mlv.fr (Remi Forax) Date: Fri, 02 Nov 2012 17:48:55 +0100 Subject: Parametrized method and cyclic inference Message-ID: <5093F977.8090101@univ-mlv.fr> Hi guys, I've tried to take a big corpus of code and to refactor all inner-classes to use lambda instead. The good news is that on 23 uses of inner classes, 20 can be retrofited to use lambdas because the target type is a SAM and they don't require a strong identity (this is not used). The bad news is that among the 20 that can be retrofited, 17 can not be retrofited using the syntax that doesn't specified the type of the formal parameter i.e. the natural syntax because the compiler complains that there is a cyclic inference. The 17 snippets of code can be covered by 3 cases: static void m(T t1, T t2) { // empty } public static void main(String[] args) { m(x -> 3, x -> 4); // case 1 Set> set = Collections.singleton(x -> 3); // case 2 List> list = Arrays.asList(x -> 1); // case 3 } To sumarrize, it's currently impossible to call a parametrized method with an untyped lambda, the inference will just choke. I think instead that if there is a cyclic inference, the return type should be used to try to infer the formal parameter type of the lambda, at least, it will solve case 2 and 3. regards, R?mi From sam at sampullara.com Fri Nov 2 13:19:27 2012 From: sam at sampullara.com (Sam Pullara) Date: Fri, 2 Nov 2012 13:19:27 -0700 Subject: Parametrized method and cyclic inference In-Reply-To: <5093F977.8090101@univ-mlv.fr> References: <5093F977.8090101@univ-mlv.fr> Message-ID: I've run into this case a lot when building things. I would love it if it were fixed. Sam On Fri, Nov 2, 2012 at 9:48 AM, Remi Forax wrote: > Hi guys, > I've tried to take a big corpus of code and to refactor all inner-classes > to use lambda instead. > > The good news is that on 23 uses of inner classes, 20 can be retrofited to > use lambdas > because the target type is a SAM and they don't require a strong identity > (this is not used). > The bad news is that among the 20 that can be retrofited, 17 can not be > retrofited using > the syntax that doesn't specified the type of the formal parameter i.e. > the natural syntax > because the compiler complains that there is a cyclic inference. > > The 17 snippets of code can be covered by 3 cases: > static void m(T t1, T t2) { > // empty > } > > public static void main(String[] args) { > m(x -> 3, x -> 4); // case 1 > Set> set = Collections.singleton(x -> 3); // > case 2 > List> list = Arrays.asList(x -> 1); // case 3 > } > > To sumarrize, it's currently impossible to call a parametrized method with > an untyped lambda, > the inference will just choke. > > I think instead that if there is a cyclic inference, > the return type should be used to try to infer the formal parameter type > of the lambda, > at least, it will solve case 2 and 3. > > regards, > R?mi > > -------------- next part -------------- An HTML attachment was scrubbed... URL: http://mail.openjdk.java.net/pipermail/lambda-spec-experts/attachments/20121102/b8e1ac7a/attachment.html From brian.goetz at oracle.com Fri Nov 2 13:35:00 2012 From: brian.goetz at oracle.com (Brian Goetz) Date: Fri, 02 Nov 2012 16:35:00 -0400 Subject: Parametrized method and cyclic inference In-Reply-To: References: <5093F977.8090101@univ-mlv.fr> Message-ID: <50942E74.1060805@oracle.com> We're working on that! On 11/2/2012 4:19 PM, Sam Pullara wrote: > I've run into this case a lot when building things. I would love it if > it were fixed. > > Sam > > On Fri, Nov 2, 2012 at 9:48 AM, Remi Forax > wrote: > > Hi guys, > I've tried to take a big corpus of code and to refactor all > inner-classes to use lambda instead. > > The good news is that on 23 uses of inner classes, 20 can be > retrofited to use lambdas > because the target type is a SAM and they don't require a strong > identity (this is not used). > The bad news is that among the 20 that can be retrofited, 17 can not > be retrofited using > the syntax that doesn't specified the type of the formal parameter > i.e. the natural syntax > because the compiler complains that there is a cyclic inference. > > The 17 snippets of code can be covered by 3 cases: > static void m(T t1, T t2) { > // empty > } > > public static void main(String[] args) { > m(x -> 3, x -> 4); // case 1 > Set> set = Collections.singleton(x -> > 3); // case 2 > List> list = Arrays.asList(x -> 1); // > case 3 > } > > To sumarrize, it's currently impossible to call a parametrized > method with an untyped lambda, > the inference will just choke. > > I think instead that if there is a cyclic inference, > the return type should be used to try to infer the formal parameter > type of the lambda, > at least, it will solve case 2 and 3. > > regards, > R?mi > > From daniel.smith at oracle.com Fri Nov 2 15:19:26 2012 From: daniel.smith at oracle.com (Dan Smith) Date: Fri, 2 Nov 2012 16:19:26 -0600 Subject: Parametrized method and cyclic inference In-Reply-To: <5093F977.8090101@univ-mlv.fr> References: <5093F977.8090101@univ-mlv.fr> Message-ID: <2DC795D0-30B7-45F5-9976-680F390066F4@oracle.com> On Nov 2, 2012, at 10:48 AM, Remi Forax wrote: > Hi guys, > I've tried to take a big corpus of code and to refactor all inner-classes to use lambda instead. > > The good news is that on 23 uses of inner classes, 20 can be retrofited to use lambdas > because the target type is a SAM and they don't require a strong identity (this is not used). > The bad news is that among the 20 that can be retrofited, 17 can not be retrofited using > the syntax that doesn't specified the type of the formal parameter i.e. the natural syntax > because the compiler complains that there is a cyclic inference. > > The 17 snippets of code can be covered by 3 cases: > static void m(T t1, T t2) { > // empty > } > > public static void main(String[] args) { > m(x -> 3, x -> 4); // case 1 > Set> set = Collections.singleton(x -> 3); // case 2 > List> list = Arrays.asList(x -> 1); // case 3 > } > > To sumarrize, it's currently impossible to call a parametrized method with an untyped lambda, > the inference will just choke. > > I think instead that if there is a cyclic inference, > the return type should be used to try to infer the formal parameter type of the lambda, > at least, it will solve case 2 and 3. Thanks! Feedback from real code is very useful. I'm confused about your emphasis on the implicit parameter type -- if your lambdas look like '(Integer x) -> 3', don't you still get an error? Yes, #1 is hopeless -- there is no type anywhere to tell us what the lambdas represent. #2 and #3 are interesting. In general, we've nailed down a strategy for inference that depends on a target type. But this is special. The target type is an inference variable, T. Note that this is _not_ a functional interface. Everything we've done to this point has bailed out early if the target of a lambda is not a functional interface. An alternative would be to initially hope that T will be a functional interface, wait for T to be resolved, and then go from there. There are aspects of that that feel a little more complex than I would like, but it's probably doable. How important are these use cases to you? ?Dan From daniel.smith at oracle.com Fri Nov 2 15:23:13 2012 From: daniel.smith at oracle.com (Dan Smith) Date: Fri, 2 Nov 2012 16:23:13 -0600 Subject: Parametrized method and cyclic inference In-Reply-To: References: <5093F977.8090101@univ-mlv.fr> Message-ID: On Nov 2, 2012, at 2:19 PM, Sam Pullara wrote: > I've run into this case a lot when building things. I would love it if it were fixed. Can you be more specific about "this case"? Does it look more like this (something we've developed a good solution for): Predicate ps = Predicate.and(x -> !x.isEmpty(), x -> x.matches("foo.*")); Or this (Remi's example): Set sr = Collections.singleton(() -> System.gc()); (The difference being that a functional interface appears in the declaration of 'and', but not in the declaration of 'singleton'.) ?Dan From forax at univ-mlv.fr Fri Nov 2 17:27:51 2012 From: forax at univ-mlv.fr (Remi Forax) Date: Sat, 03 Nov 2012 01:27:51 +0100 Subject: Parametrized method and cyclic inference In-Reply-To: <2DC795D0-30B7-45F5-9976-680F390066F4@oracle.com> References: <5093F977.8090101@univ-mlv.fr> <2DC795D0-30B7-45F5-9976-680F390066F4@oracle.com> Message-ID: <50946507.7070206@univ-mlv.fr> On 11/02/2012 11:19 PM, Dan Smith wrote: > On Nov 2, 2012, at 10:48 AM, Remi Forax wrote: > >> Hi guys, >> I've tried to take a big corpus of code and to refactor all inner-classes to use lambda instead. >> >> The good news is that on 23 uses of inner classes, 20 can be retrofited to use lambdas >> because the target type is a SAM and they don't require a strong identity (this is not used). >> The bad news is that among the 20 that can be retrofited, 17 can not be retrofited using >> the syntax that doesn't specified the type of the formal parameter i.e. the natural syntax >> because the compiler complains that there is a cyclic inference. >> >> The 17 snippets of code can be covered by 3 cases: >> static void m(T t1, T t2) { >> // empty >> } >> >> public static void main(String[] args) { >> m(x -> 3, x -> 4); // case 1 >> Set> set = Collections.singleton(x -> 3); // case 2 >> List> list = Arrays.asList(x -> 1); // case 3 >> } >> >> To sumarrize, it's currently impossible to call a parametrized method with an untyped lambda, >> the inference will just choke. >> >> I think instead that if there is a cyclic inference, >> the return type should be used to try to infer the formal parameter type of the lambda, >> at least, it will solve case 2 and 3. > Thanks! Feedback from real code is very useful. > > I'm confused about your emphasis on the implicit parameter type -- if your lambdas look like '(Integer x) -> 3', don't you still get an error? No. Only, x -> 3 raises a cyclic inference error. > > Yes, #1 is hopeless -- there is no type anywhere to tell us what the lambdas represent. I agree. But what about, m((String x) -> 3, x -> 4), i.e when on argument provide full types ? > > #2 and #3 are interesting. In general, we've nailed down a strategy for inference that depends on a target type. But this is special. > > The target type is an inference variable, T. Note that this is _not_ a functional interface. Everything we've done to this point has bailed out early if the target of a lambda is not a functional interface. > > An alternative would be to initially hope that T will be a functional interface, wait for T to be resolved, and then go from there. There are aspects of that that feel a little more complex than I would like, but it's probably doable. > > How important are these use cases to you? 17 out 23 usages of lambdas requires to declare parameters, it's perhaps just this codebase, but the question that comes in my mind is: Is it a good idea to provide a special syntax (no need to declare parameter type in lambda) if this syntax can rarely be used ? So I think these use cases are important if we want our users to be able to use Arrays.asList(), Collections.addAll() or Collections.singleton*() with a lambda as argument. > > ?Dan R?mi From forax at univ-mlv.fr Fri Nov 2 17:35:47 2012 From: forax at univ-mlv.fr (Remi Forax) Date: Sat, 03 Nov 2012 01:35:47 +0100 Subject: Parametrized method and cyclic inference In-Reply-To: <2DC795D0-30B7-45F5-9976-680F390066F4@oracle.com> References: <5093F977.8090101@univ-mlv.fr> <2DC795D0-30B7-45F5-9976-680F390066F4@oracle.com> Message-ID: <509466E3.1030109@univ-mlv.fr> On 11/02/2012 11:19 PM, Dan Smith wrote: > On Nov 2, 2012, at 10:48 AM, Remi Forax wrote: > >> Hi guys, >> I've tried to take a big corpus of code and to refactor all inner-classes to use lambda instead. >> >> The good news is that on 23 uses of inner classes, 20 can be retrofited to use lambdas >> because the target type is a SAM and they don't require a strong identity (this is not used). >> The bad news is that among the 20 that can be retrofited, 17 can not be retrofited using >> the syntax that doesn't specified the type of the formal parameter i.e. the natural syntax >> because the compiler complains that there is a cyclic inference. >> >> The 17 snippets of code can be covered by 3 cases: >> static void m(T t1, T t2) { >> // empty >> } >> >> public static void main(String[] args) { >> m(x -> 3, x -> 4); // case 1 >> Set> set = Collections.singleton(x -> 3); // case 2 >> List> list = Arrays.asList(x -> 1); // case 3 >> } >> >> To sumarrize, it's currently impossible to call a parametrized method with an untyped lambda, >> the inference will just choke. >> >> I think instead that if there is a cyclic inference, >> the return type should be used to try to infer the formal parameter type of the lambda, >> at least, it will solve case 2 and 3. > Thanks! Feedback from real code is very useful. > #2 and #3 are interesting. In general, we've nailed down a strategy for inference that depends on a target type. But this is special. > > The target type is an inference variable, T. Note that this is _not_ a functional interface. Everything we've done to this point has bailed out early if the target of a lambda is not a functional interface. > > An alternative would be to initially hope that T will be a functional interface, wait for T to be resolved, and then go from there. There are aspects of that that feel a little more complex than I would like, but it's probably doable. I think that if we have cyclic inference, it's better to back propagate the result type and to try to use it as a function interface. By example, for Set> set = Collections.singleton(x -> 3); Clearly, it's a cyclic inference, because singleton is defined like this Set signleton(T element), instead of trying to know if T is a function interface, in my opinion, it's better to try to infers T from the result type, here, Set>, because the return type is Set, then T is Mapper, and now you can restart your inference of the lambda expression with the type of T. Note that this algorithm also works with diamond syntax which is the other expression with lambda expression that need the target type, i.e. works backward in the type checker. R?mi From sam at sampullara.com Fri Nov 2 21:11:27 2012 From: sam at sampullara.com (Sam Pullara) Date: Fri, 2 Nov 2012 21:11:27 -0700 Subject: Parametrized method and cyclic inference In-Reply-To: <509466E3.1030109@univ-mlv.fr> References: <5093F977.8090101@univ-mlv.fr> <2DC795D0-30B7-45F5-9976-680F390066F4@oracle.com> <509466E3.1030109@univ-mlv.fr> Message-ID: <6CD7A430-5A98-4DB8-ABB5-DA9059D76FE6@sampullara.com> I've also had issues with ?:, <> in combination with lambda return types. It looks like this I because I expect the type declaration on the left to flow through. Sam Example declaration: public static Match match(Extractor e, Mapper c) { Works: Match matcher = match((String s) -> s.equals("1") ? new Optional<>(1) : null, s -> 1); Doesn't work: Match matcher2 = match(s -> s.equals("1") ? new Optional<>(1) : null, s -> 1); error: method match in class Match cannot be applied to given types; required: Extractor,Mapper found: (s)->s.equ[...] null,(s)->1 reason: cyclic inference - cannot infer target type for given lambda/method reference expression where T#1,V#1,W,T#2,V#2 are type-variables: T#1 extends Object declared in method match(Extractor,Mapper) V#1 extends Object declared in method match(Extractor,Mapper) W extends Object declared in method match(Extractor,Mapper) T#2 extends Object declared in class Match V#2 extends Object declared in class Match Declaration: public Match or(Extractor e, Mapper c) { Works: Match matcher3 = matcher.or(s -> s.equals("2") ? new Optional<>(2) : Optional.empty(), i -> 2); Doesn't work: Match matcher3 = matcher.or(s -> s.equals("2") ? new Optional<>(2) : Optional.empty(), i -> 2); error: no suitable method found for or((s)->s.equ[...]pty(),(i)->2) method Match.or(Match,Extractor,Mapper) is not applicable (cannot infer type-variable(s) T#1,V#1,W#1 (actual and formal argument lists differ in length)) method Match.or(Extractor,Mapper) is not applicable (cannot infer type-variable(s) W#2 (argument mismatch; bad return type in lambda expression bad type in conditional expression; Optional cannot be converted to Optional)) where T#1,V#1,W#1,W#2,T#2,V#2 are type-variables: T#1 extends Object declared in method or(Match,Extractor,Mapper) V#1 extends Object declared in method or(Match,Extractor,Mapper) W#1 extends Object declared in method or(Match,Extractor,Mapper) W#2 extends Object declared in method or(Extractor,Mapper) T#2 extends Object declared in class Match V#2 extends Object declared in class Match On Nov 2, 2012, at 5:35 PM, Remi Forax wrote: > On 11/02/2012 11:19 PM, Dan Smith wrote: >> On Nov 2, 2012, at 10:48 AM, Remi Forax wrote: >> >>> Hi guys, >>> I've tried to take a big corpus of code and to refactor all inner-classes to use lambda instead. >>> >>> The good news is that on 23 uses of inner classes, 20 can be retrofited to use lambdas >>> because the target type is a SAM and they don't require a strong identity (this is not used). >>> The bad news is that among the 20 that can be retrofited, 17 can not be retrofited using >>> the syntax that doesn't specified the type of the formal parameter i.e. the natural syntax >>> because the compiler complains that there is a cyclic inference. >>> >>> The 17 snippets of code can be covered by 3 cases: >>> static void m(T t1, T t2) { >>> // empty >>> } >>> >>> public static void main(String[] args) { >>> m(x -> 3, x -> 4); // case 1 >>> Set> set = Collections.singleton(x -> 3); // case 2 >>> List> list = Arrays.asList(x -> 1); // case 3 >>> } >>> >>> To sumarrize, it's currently impossible to call a parametrized method with an untyped lambda, >>> the inference will just choke. >>> >>> I think instead that if there is a cyclic inference, >>> the return type should be used to try to infer the formal parameter type of the lambda, >>> at least, it will solve case 2 and 3. >> Thanks! Feedback from real code is very useful. > > >> #2 and #3 are interesting. In general, we've nailed down a strategy for inference that depends on a target type. But this is special. >> >> The target type is an inference variable, T. Note that this is _not_ a functional interface. Everything we've done to this point has bailed out early if the target of a lambda is not a functional interface. >> >> An alternative would be to initially hope that T will be a functional interface, wait for T to be resolved, and then go from there. There are aspects of that that feel a little more complex than I would like, but it's probably doable. > > I think that if we have cyclic inference, it's better to back propagate the result type and to try to use it as a function interface. > > By example, for > > Set> set = Collections.singleton(x -> 3); > > Clearly, it's a cyclic inference, because singleton is defined like this Set signleton(T element), > instead of trying to know if T is a function interface, in my opinion, it's better to try to infers T from the result type, > here, Set>, because the return type is Set, then T is Mapper, > and now you can restart your inference of the lambda expression with the type of T. > > Note that this algorithm also works with diamond syntax which is the other expression with lambda expression > that need the target type, i.e. works backward in the type checker. > > R?mi > From brian.goetz at oracle.com Sat Nov 3 05:01:47 2012 From: brian.goetz at oracle.com (Brian Goetz) Date: Sat, 03 Nov 2012 08:01:47 -0400 Subject: Parametrized method and cyclic inference In-Reply-To: <6CD7A430-5A98-4DB8-ABB5-DA9059D76FE6@sampullara.com> References: <5093F977.8090101@univ-mlv.fr> <2DC795D0-30B7-45F5-9976-680F390066F4@oracle.com> <509466E3.1030109@univ-mlv.fr> <6CD7A430-5A98-4DB8-ABB5-DA9059D76FE6@sampullara.com> Message-ID: <509507AB.6070606@oracle.com> Yeah, conditionals are awful. We're working on them too. But lots of historical landmines to avoid :( On 11/3/2012 12:11 AM, Sam Pullara wrote: > I've also had issues with ?:, <> in combination with lambda return types. It looks like this I because I expect the type declaration on the left to flow through. > > Sam > > Example declaration: > > public static Match match(Extractor e, Mapper c) { > > Works: > Match matcher = match((String s) -> s.equals("1") ? new Optional<>(1) : null, s -> 1); > > Doesn't work: > Match matcher2 = match(s -> s.equals("1") ? new Optional<>(1) : null, s -> 1); > > error: method match in class Match cannot be applied to given types; > required: Extractor,Mapper > found: (s)->s.equ[...] null,(s)->1 > reason: cyclic inference - cannot infer target type for given lambda/method reference expression > where T#1,V#1,W,T#2,V#2 are type-variables: > T#1 extends Object declared in method match(Extractor,Mapper) > V#1 extends Object declared in method match(Extractor,Mapper) > W extends Object declared in method match(Extractor,Mapper) > T#2 extends Object declared in class Match > V#2 extends Object declared in class Match > > Declaration: > public Match or(Extractor e, Mapper c) { > > Works: > Match matcher3 = matcher.or(s -> s.equals("2") ? new Optional<>(2) : Optional.empty(), i -> 2); > > Doesn't work: > Match matcher3 = matcher.or(s -> s.equals("2") ? new Optional<>(2) : Optional.empty(), i -> 2); > > error: no suitable method found for or((s)->s.equ[...]pty(),(i)->2) > method Match.or(Match,Extractor,Mapper) is not applicable > (cannot infer type-variable(s) T#1,V#1,W#1 > (actual and formal argument lists differ in length)) > method Match.or(Extractor,Mapper) is not applicable > (cannot infer type-variable(s) W#2 > (argument mismatch; bad return type in lambda expression > bad type in conditional expression; Optional cannot be converted to Optional)) > where T#1,V#1,W#1,W#2,T#2,V#2 are type-variables: > T#1 extends Object declared in method or(Match,Extractor,Mapper) > V#1 extends Object declared in method or(Match,Extractor,Mapper) > W#1 extends Object declared in method or(Match,Extractor,Mapper) > W#2 extends Object declared in method or(Extractor,Mapper) > T#2 extends Object declared in class Match > V#2 extends Object declared in class Match > > On Nov 2, 2012, at 5:35 PM, Remi Forax wrote: > >> On 11/02/2012 11:19 PM, Dan Smith wrote: >>> On Nov 2, 2012, at 10:48 AM, Remi Forax wrote: >>> >>>> Hi guys, >>>> I've tried to take a big corpus of code and to refactor all inner-classes to use lambda instead. >>>> >>>> The good news is that on 23 uses of inner classes, 20 can be retrofited to use lambdas >>>> because the target type is a SAM and they don't require a strong identity (this is not used). >>>> The bad news is that among the 20 that can be retrofited, 17 can not be retrofited using >>>> the syntax that doesn't specified the type of the formal parameter i.e. the natural syntax >>>> because the compiler complains that there is a cyclic inference. >>>> >>>> The 17 snippets of code can be covered by 3 cases: >>>> static void m(T t1, T t2) { >>>> // empty >>>> } >>>> >>>> public static void main(String[] args) { >>>> m(x -> 3, x -> 4); // case 1 >>>> Set> set = Collections.singleton(x -> 3); // case 2 >>>> List> list = Arrays.asList(x -> 1); // case 3 >>>> } >>>> >>>> To sumarrize, it's currently impossible to call a parametrized method with an untyped lambda, >>>> the inference will just choke. >>>> >>>> I think instead that if there is a cyclic inference, >>>> the return type should be used to try to infer the formal parameter type of the lambda, >>>> at least, it will solve case 2 and 3. >>> Thanks! Feedback from real code is very useful. >> >> >>> #2 and #3 are interesting. In general, we've nailed down a strategy for inference that depends on a target type. But this is special. >>> >>> The target type is an inference variable, T. Note that this is _not_ a functional interface. Everything we've done to this point has bailed out early if the target of a lambda is not a functional interface. >>> >>> An alternative would be to initially hope that T will be a functional interface, wait for T to be resolved, and then go from there. There are aspects of that that feel a little more complex than I would like, but it's probably doable. >> >> I think that if we have cyclic inference, it's better to back propagate the result type and to try to use it as a function interface. >> >> By example, for >> >> Set> set = Collections.singleton(x -> 3); >> >> Clearly, it's a cyclic inference, because singleton is defined like this Set signleton(T element), >> instead of trying to know if T is a function interface, in my opinion, it's better to try to infers T from the result type, >> here, Set>, because the return type is Set, then T is Mapper, >> and now you can restart your inference of the lambda expression with the type of T. >> >> Note that this algorithm also works with diamond syntax which is the other expression with lambda expression >> that need the target type, i.e. works backward in the type checker. >> >> R?mi >> > From daniel.smith at oracle.com Sat Nov 3 10:40:22 2012 From: daniel.smith at oracle.com (Dan Smith) Date: Sat, 3 Nov 2012 11:40:22 -0600 Subject: Parametrized method and cyclic inference In-Reply-To: <50946507.7070206@univ-mlv.fr> References: <5093F977.8090101@univ-mlv.fr> <2DC795D0-30B7-45F5-9976-680F390066F4@oracle.com> <50946507.7070206@univ-mlv.fr> Message-ID: On Nov 2, 2012, at 6:27 PM, Remi Forax wrote: >> Thanks! Feedback from real code is very useful. >> >> I'm confused about your emphasis on the implicit parameter type -- if your lambdas look like '(Integer x) -> 3', don't you still get an error? > > No. Only, x -> 3 raises a cyclic inference error. I tried compiling this: Set> set = Collections.singleton((Integer x) -> 3); And got an error: SingletonLambda.java:6: error: method singleton in class Collections cannot be applied to given types; Set> set = Collections.singleton((Integer x) -> 3); ^ required: T found: (Integer x)->3 reason: cyclic inference - cannot infer target type for given lambda/method reference expression where T is a type-variable: T extends Object declared in method singleton(T) This matches my expectation -- the compiler has to decide what the type of the lambda expression is before it looks at the target; there's no way to know that 'Mapper' is the intended type. So, are the use cases you're actually concerned about different than 'Collections.singleton'? Or are you mistaken about adding an explicit parameter type fixing the problem? Or maybe we're working with different compilers? >> Yes, #1 is hopeless -- there is no type anywhere to tell us what the lambdas represent. > > I agree. > But what about, m((String x) -> 3, x -> 4), > i.e when on argument provide full types ? What is the type of the lambda expression? We'd have to pull a functional interface out of the air. >> How important are these use cases to you? > > 17 out 23 usages of lambdas requires to declare parameters, it's perhaps just this codebase, but the question that comes in my mind is: > Is it a good idea to provide a special syntax (no need to declare parameter type in lambda) if this syntax can rarely be used ? Agreed; it is our intent that inference should be powerful enough to make explicit parameter types generally unnecessary. Any of your use cases that fail with implicit parameters but succeed with explicit parameters are examples of where the inference implementation likely needs to be improved. But I don't think 'singleton' falls into this category -- hence my question of whether use cases like 'singleton' are important. (More generally, I'm talking about methods that don't mention functional interfaces in their declarations.) ?Dan From forax at univ-mlv.fr Sat Nov 3 11:08:34 2012 From: forax at univ-mlv.fr (Remi Forax) Date: Sat, 03 Nov 2012 19:08:34 +0100 Subject: Parametrized method and cyclic inference In-Reply-To: References: <5093F977.8090101@univ-mlv.fr> <2DC795D0-30B7-45F5-9976-680F390066F4@oracle.com> <50946507.7070206@univ-mlv.fr> Message-ID: <50955DA2.3080204@univ-mlv.fr> On 11/03/2012 06:40 PM, Dan Smith wrote: > On Nov 2, 2012, at 6:27 PM, Remi Forax wrote: > >>> Thanks! Feedback from real code is very useful. >>> >>> I'm confused about your emphasis on the implicit parameter type -- if your lambdas look like '(Integer x) -> 3', don't you still get an error? >> No. Only, x -> 3 raises a cyclic inference error. Hi Dan, > I tried compiling this: > > Set> set = Collections.singleton((Integer x) -> 3); > > And got an error: > > SingletonLambda.java:6: error: method singleton in class Collections cannot be applied to given types; > Set> set = Collections.singleton((Integer x) -> 3); > ^ > required: T > found: (Integer x)->3 > reason: cyclic inference - cannot infer target type for given lambda/method reference expression > where T is a type-variable: > T extends Object declared in method singleton(T) > > This matches my expectation -- the compiler has to decide what the type of the lambda expression is before it looks at the target; Yes, the idea is to enhance the existing inference algorithm to solve the cyclic inference problems (at least some of them) > there's no way to know that 'Mapper' is the intended type. Look at the expected type on the right, as the target typing of lambda does if it's an assignment and not a method call. This works, Mapper mapper = x -> 3; but if you enclose the lambda in a parametrized method that takes a T and return a T, a kind of identity on type, the inference doesn't use the target type anymore. I think this should be fixed, and as you said even if you type the formal parameter of the lambda, it may still not work. > > So, are the use cases you're actually concerned about different than 'Collections.singleton'? No, I've simplified the problem as said in my first mail. There are several calls that takes a T and return a Foo of T in the code base, I've summarized them by saying there are equivalent to Collections.singleton(). It was a mistake as you demonstrate because the inference algorithm works differently if T is bound by a function interface or not, something I've not noticed until you mention it. > Or are you mistaken about adding an explicit parameter type fixing the problem? Or maybe we're working with different compilers? > >>> Yes, #1 is hopeless -- there is no type anywhere to tell us what the lambdas represent. >> I agree. >> But what about, m((String x) -> 3, x -> 4), >> i.e when on argument provide full types ? > What is the type of the lambda expression? We'd have to pull a functional interface out of the air. yes, right. > >>> How important are these use cases to you? >> 17 out 23 usages of lambdas requires to declare parameters, it's perhaps just this codebase, but the question that comes in my mind is: >> Is it a good idea to provide a special syntax (no need to declare parameter type in lambda) if this syntax can rarely be used ? > > Agreed; it is our intent that inference should be powerful enough to make explicit parameter types generally unnecessary. Any of your use cases that fail with implicit parameters but succeed with explicit parameters are examples of where the inference implementation likely needs to be improved. > > But I don't think 'singleton' falls into this category -- hence my question of whether use cases like 'singleton' are important. (More generally, I'm talking about methods that don't mention functional interfaces in their declarations.) What your are suggesting, correct me if I'm wrong is instead of writing T foo(T element), I should write T foo(T element) for every function interfaces that exist ? This seems to defeat the purpose of parametrized methods. > > ?Dan R?mi From daniel.smith at oracle.com Sat Nov 3 13:43:45 2012 From: daniel.smith at oracle.com (Dan Smith) Date: Sat, 3 Nov 2012 14:43:45 -0600 Subject: Parametrized method and cyclic inference In-Reply-To: <50955DA2.3080204@univ-mlv.fr> References: <5093F977.8090101@univ-mlv.fr> <2DC795D0-30B7-45F5-9976-680F390066F4@oracle.com> <50946507.7070206@univ-mlv.fr> <50955DA2.3080204@univ-mlv.fr> Message-ID: On Nov 3, 2012, at 12:08 PM, Remi Forax wrote: > On 11/03/2012 06:40 PM, Dan Smith wrote: >> On Nov 2, 2012, at 6:27 PM, Remi Forax wrote: >> >>>> Thanks! Feedback from real code is very useful. >>>> >>>> I'm confused about your emphasis on the implicit parameter type -- if your lambdas look like '(Integer x) -> 3', don't you still get an error? >>> No. Only, x -> 3 raises a cyclic inference error. > > Hi Dan, > >> I tried compiling this: >> >> Set> set = Collections.singleton((Integer x) -> 3); >> >> And got an error: >> >> SingletonLambda.java:6: error: method singleton in class Collections cannot be applied to given types; >> Set> set = Collections.singleton((Integer x) -> 3); >> ^ >> required: T >> found: (Integer x)->3 >> reason: cyclic inference - cannot infer target type for given lambda/method reference expression >> where T is a type-variable: >> T extends Object declared in method singleton(T) >> >> This matches my expectation -- the compiler has to decide what the type of the lambda expression is before it looks at the target; > > Yes, the idea is to enhance the existing inference algorithm to solve the cyclic inference problems (at least some of them) Wait -- see your response above: "No. Only, x -> 3 raises a cyclic inference error." My example uses "(Integer x) -> 3". Let me ask again: which, if any, errors are you able to fix by adding a parameter type? My expectation is "none of them," unless we're lumping together two different kinds of problems. >> So, are the use cases you're actually concerned about different than 'Collections.singleton'? > > No, I've simplified the problem as said in my first mail. There are several calls that takes a T and return a Foo of T in the code base, > I've summarized them by saying there are equivalent to Collections.singleton(). > It was a mistake as you demonstrate because the inference algorithm works differently if T is bound by a function interface or not, > something I've not noticed until you mention it. If I understand correctly, all of the errors you're citing can be described as "takes a T and return a Foo of T". That's the main thing I care about -- whether the method's parameter type is "T" (inferred to be a functional interface type) or "FunctionalInterface". > What your are suggesting, correct me if I'm wrong is instead of writing T foo(T element), I should write T foo(T element) for every function interfaces that exist ? > This seems to defeat the purpose of parametrized methods. No, I'm tentatively saying this is a new problem we need to fix. We've been actively working on a solution to 'Predicate p = negate(x -> x.isEmpty())' -- methods that expect a parameterization of a functional interface, and need to infer the parameters from the target type. I'm trying to decide whether your examples fit this description, or whether we need to do some new work which will handle things like 'Set> s = singleton(x -> x.isEmpty())'. My impression is that, yes, we need to handle this case too, but the comments you made about explicit vs. implicit parameters made me uncertain about this impression. ?Dan From forax at univ-mlv.fr Sat Nov 3 14:07:59 2012 From: forax at univ-mlv.fr (Remi Forax) Date: Sat, 03 Nov 2012 22:07:59 +0100 Subject: Parametrized method and cyclic inference In-Reply-To: References: <5093F977.8090101@univ-mlv.fr> <2DC795D0-30B7-45F5-9976-680F390066F4@oracle.com> <50946507.7070206@univ-mlv.fr> <50955DA2.3080204@univ-mlv.fr> Message-ID: <509587AF.80508@univ-mlv.fr> On 11/03/2012 09:43 PM, Dan Smith wrote: > On Nov 3, 2012, at 12:08 PM, Remi Forax wrote: > >> On 11/03/2012 06:40 PM, Dan Smith wrote: >>> On Nov 2, 2012, at 6:27 PM, Remi Forax wrote: >>> >>>>> Thanks! Feedback from real code is very useful. >>>>> >>>>> I'm confused about your emphasis on the implicit parameter type -- if your lambdas look like '(Integer x) -> 3', don't you still get an error? >>>> No. Only, x -> 3 raises a cyclic inference error. >> Hi Dan, >> >>> I tried compiling this: >>> >>> Set> set = Collections.singleton((Integer x) -> 3); >>> >>> And got an error: >>> >>> SingletonLambda.java:6: error: method singleton in class Collections cannot be applied to given types; >>> Set> set = Collections.singleton((Integer x) -> 3); >>> ^ >>> required: T >>> found: (Integer x)->3 >>> reason: cyclic inference - cannot infer target type for given lambda/method reference expression >>> where T is a type-variable: >>> T extends Object declared in method singleton(T) >>> >>> This matches my expectation -- the compiler has to decide what the type of the lambda expression is before it looks at the target; >> Yes, the idea is to enhance the existing inference algorithm to solve the cyclic inference problems (at least some of them) > Wait -- see your response above: "No. Only, x -> 3 raises a cyclic inference error." My example uses "(Integer x) -> 3". > > Let me ask again: which, if any, errors are you able to fix by adding a parameter type? My expectation is "none of them," unless we're lumping together two different kinds of problems. here is an example, private static void foo(Mapper... r) { ... } ... foo(x -> 2); // doesn't compile foo((String x) -> 2); // compile > >>> So, are the use cases you're actually concerned about different than 'Collections.singleton'? >> No, I've simplified the problem as said in my first mail. There are several calls that takes a T and return a Foo of T in the code base, >> I've summarized them by saying there are equivalent to Collections.singleton(). >> It was a mistake as you demonstrate because the inference algorithm works differently if T is bound by a function interface or not, >> something I've not noticed until you mention it. > If I understand correctly, all of the errors you're citing can be described as "takes a T and return a Foo of T". some of them, the one covered by the sample 1 > That's the main thing I care about -- whether the method's parameter type is "T" (inferred to be a functional interface type) or "FunctionalInterface". It's T inferred as a functional interface, mostly. Sometimes T is bound by a functional interface. > >> What your are suggesting, correct me if I'm wrong is instead of writing T foo(T element), I should write T foo(T element) for every function interfaces that exist ? >> This seems to defeat the purpose of parametrized methods. > No, I'm tentatively saying this is a new problem we need to fix. > > We've been actively working on a solution to 'Predicate p = negate(x -> x.isEmpty())' -- methods that expect a parameterization of a functional interface, and need to infer the parameters from the target type. I'm trying to decide whether your examples fit this description, or whether we need to do some new work which will handle things like 'Set> s = singleton(x -> x.isEmpty())'. My impression is that, yes, we need to handle this case too, but the comments you made about explicit vs. implicit parameters made me uncertain about this impression. I've said, sorry to write that the problem is just implicit vs explicit, it's more complex than that. > > ?Dan R?mi