From amaembo at gmail.com Thu Oct 5 05:21:01 2017 From: amaembo at gmail.com (Tagir Valeev) Date: Thu, 5 Oct 2017 12:21:01 +0700 Subject: JEP 302: Underscore as enhanced for loop parameter? Message-ID: Hello! I think underscore could be allowed as an enhanced for parameter. In rare cases it's necessary to iterate over Iterable without using the elements like here: long countElements(Iterable iterable) { long count = 0; for(Object _ : iterable) count++; return count; } Here we have a place where we're syntactically forced to declare a variable, but we don't need one. Similarly to a catch block this perfectly fits the underscore use cases. This would also help to perform code static analysis. It's common for IDEs to warn if a loop variable is unused (which could be a bug like another variable is used instead by mistake). Using underscore we explicitly say that we don't need a variable here. In IntelliJ IDEA we suggest using an "ignored" name in such case, but it's still a valid name and can be used accidentally or clashed with another name. Sorry if this was already discussed, I wasn't able to find any public discussions on this topic. With best regards, Tagir Valeev. From brian.goetz at oracle.com Thu Oct 5 23:10:03 2017 From: brian.goetz at oracle.com (Brian Goetz) Date: Thu, 5 Oct 2017 19:10:03 -0400 Subject: JEP 302: Underscore as enhanced for loop parameter? In-Reply-To: References: Message-ID: <0d49f58b-7999-e97d-2e60-c8f4c46ce2b0@oracle.com> Yes, seems reasonable. On 10/5/2017 1:21 AM, Tagir Valeev wrote: > Hello! > > I think underscore could be allowed as an enhanced for parameter. In > rare cases it's necessary to iterate over Iterable without using the > elements like here: > > long countElements(Iterable iterable) { > long count = 0; > for(Object _ : iterable) count++; > return count; > } > > Here we have a place where we're syntactically forced to declare a > variable, but we don't need one. Similarly to a catch block this > perfectly fits the underscore use cases. This would also help to > perform code static analysis. It's common for IDEs to warn if a loop > variable is unused (which could be a bug like another variable is used > instead by mistake). Using underscore we explicitly say that we don't > need a variable here. In IntelliJ IDEA we suggest using an "ignored" > name in such case, but it's still a valid name and can be used > accidentally or clashed with another name. > > Sorry if this was already discussed, I wasn't able to find any public > discussions on this topic. > > With best regards, > Tagir Valeev. From forax at univ-mlv.fr Fri Oct 6 04:56:43 2017 From: forax at univ-mlv.fr (Remi Forax) Date: Fri, 06 Oct 2017 04:56:43 +0000 Subject: JEP 302: Underscore as enhanced for loop parameter? In-Reply-To: <0d49f58b-7999-e97d-2e60-c8f4c46ce2b0@oracle.com> References: <0d49f58b-7999-e97d-2e60-c8f4c46ce2b0@oracle.com> Message-ID: I agree. Remi On October 6, 2017 1:10:03 AM GMT+02:00, Brian Goetz wrote: >Yes, seems reasonable. > >On 10/5/2017 1:21 AM, Tagir Valeev wrote: >> Hello! >> >> I think underscore could be allowed as an enhanced for parameter. In >> rare cases it's necessary to iterate over Iterable without using the >> elements like here: >> >> long countElements(Iterable iterable) { >> long count = 0; >> for(Object _ : iterable) count++; >> return count; >> } >> >> Here we have a place where we're syntactically forced to declare a >> variable, but we don't need one. Similarly to a catch block this >> perfectly fits the underscore use cases. This would also help to >> perform code static analysis. It's common for IDEs to warn if a loop >> variable is unused (which could be a bug like another variable is >used >> instead by mistake). Using underscore we explicitly say that we don't >> need a variable here. In IntelliJ IDEA we suggest using an "ignored" >> name in such case, but it's still a valid name and can be used >> accidentally or clashed with another name. >> >> Sorry if this was already discussed, I wasn't able to find any public >> discussions on this topic. >> >> With best regards, >> Tagir Valeev. -- Sent from my Android device with K-9 Mail. Please excuse my brevity. From mark at io7m.com Fri Oct 6 09:10:27 2017 From: mark at io7m.com (Mark Raynsford) Date: Fri, 6 Oct 2017 09:10:27 +0000 Subject: JEP 302: Underscore as enhanced for loop parameter? In-Reply-To: References: <0d49f58b-7999-e97d-2e60-c8f4c46ce2b0@oracle.com> Message-ID: <20171006091013.76d07cda@copperhead.int.arc7.info> > >On 10/5/2017 1:21 AM, Tagir Valeev wrote: > >> Hello! > >> > >> I think underscore could be allowed as an enhanced for parameter. In > >> rare cases it's necessary to iterate over Iterable without using the > >> elements like here: I agree as well. -- Mark Raynsford | http://www.io7m.com From forax at univ-mlv.fr Fri Oct 6 11:16:19 2017 From: forax at univ-mlv.fr (Remi Forax) Date: Fri, 6 Oct 2017 13:16:19 +0200 (CEST) Subject: My lambda leftovers Message-ID: <721278228.2638224.1507288579761.JavaMail.zimbra@u-pem.fr> Hi all, The JEP 302 list some improvements but I think some are missing, obviously, it's up to debate :) So here is my list of left leftovers: - support throw statement as a lambda expression I think we have already discussed informally about this one. The compiler should allow to have a lambda expression that starts with throw. so a code like this will become valid merge(key, value, (_, _) -> throw new IllegalStateException("key " + key + " already present)); - allow void to be converted to Void (by returning null) This proposal is perhaps more controversial, currently there is no way to simply convert a lambda statement to a lambda expression. So a code like will compile R sync(T initial, Function fun) { synchronized(lock) { return fun.apply(initial); } } Consumer c = System.out::println; sync("foo", c::accept); // the compiler should generate a synthetic static method that returns null This proposal is problematic because: - it implicitly produces a null, which is a bad idea - if there are several overloads, a lambda statement can now match more methods so the compiler may reject code that was previously working or worst call another method that the one that was originally selected. The other question is should the conversion be extended to work with non lambda code, i.e. consider that 'return' or an implcit 'return' can be trasformed to a return null by the compiler. Void m() { return; // the compiler generates return null; } Void m() { } // the compiler generates return null; On the positive side, it mix well with the switch expression proposed in the Pattern Matching JEP. Supplier supplier = () -> switchexpr(someValue) { case 0 -> System.out.println("foo"); default -> { /* empty */ } }; regards, R?mi [1] http://openjdk.java.net/jeps/302 From mark at io7m.com Fri Oct 6 12:19:33 2017 From: mark at io7m.com (Mark Raynsford) Date: Fri, 6 Oct 2017 12:19:33 +0000 Subject: My lambda leftovers In-Reply-To: <721278228.2638224.1507288579761.JavaMail.zimbra@u-pem.fr> References: <721278228.2638224.1507288579761.JavaMail.zimbra@u-pem.fr> Message-ID: <20171006121933.6815f2f8@copperhead.int.arc7.info> On 2017-10-06T13:16:19 +0200 Remi Forax wrote: > > - allow void to be converted to Void (by returning null) > This may not be *too* bad as long as it's strictly limited to Void, because presumably a compliant program should never have had an observable non-null value of type Void. What I was wondering is if it might be time to introduce a strictly non-null single-valued Unit (value) type. This would unfortunately be incompatible with existing Void-typed methods... -- Mark Raynsford | http://www.io7m.com From brian.goetz at oracle.com Fri Oct 6 14:04:40 2017 From: brian.goetz at oracle.com (Brian Goetz) Date: Fri, 6 Oct 2017 10:04:40 -0400 Subject: My lambda leftovers In-Reply-To: <721278228.2638224.1507288579761.JavaMail.zimbra@u-pem.fr> References: <721278228.2638224.1507288579761.JavaMail.zimbra@u-pem.fr> Message-ID: On 10/6/2017 7:16 AM, Remi Forax wrote: > Hi all, > The JEP 302 list some improvements but I think some are missing, obviously, it's up to debate :) > > So here is my list of left leftovers: > - support throw statement as a lambda expression More generally, we want to handle throw as an expression in at least some contexts.?? Lambdas are one; here's another: ??? Foo f = switch (target) { ??????? case A -> foo1; ??????? case B -> foo2; ??????? default -> throw new WrongFooException(); ??? } From amaembo at gmail.com Fri Oct 6 11:51:26 2017 From: amaembo at gmail.com (Tagir Valeev) Date: Fri, 6 Oct 2017 18:51:26 +0700 Subject: My lambda leftovers In-Reply-To: <721278228.2638224.1507288579761.JavaMail.zimbra@u-pem.fr> References: <721278228.2638224.1507288579761.JavaMail.zimbra@u-pem.fr> Message-ID: Hello! As for throw, I think it should just be converted to an expression, probably of the same type as a null literal (thus throw statement will become an expression statement). In this case it could be useful not only in lambdas, like: return list.isEmpty() ? throw new NoSuchElementException() : list.get(0); I believe, it was discussed in context of pattern matching. With best regards, Tagir Valeev. On Fri, Oct 6, 2017 at 6:16 PM, Remi Forax wrote: > Hi all, > The JEP 302 list some improvements but I think some are missing, obviously, it's up to debate :) > > So here is my list of left leftovers: > - support throw statement as a lambda expression > > I think we have already discussed informally about this one. > The compiler should allow to have a lambda expression that starts with throw. > > so a code like this will become valid > merge(key, value, (_, _) -> throw new IllegalStateException("key " + key + " already present)); > > > - allow void to be converted to Void (by returning null) > > This proposal is perhaps more controversial, currently there is no way to simply convert a lambda statement to a lambda expression. > So a code like will compile > > R sync(T initial, Function fun) { > synchronized(lock) { > return fun.apply(initial); > } > } > > Consumer c = System.out::println; > sync("foo", c::accept); // the compiler should generate a synthetic static method that returns null > > This proposal is problematic because: > - it implicitly produces a null, which is a bad idea > - if there are several overloads, a lambda statement can now match more methods so the compiler may reject code that was previously working or worst call another method that the one that was originally selected. > > > The other question is should the conversion be extended to work with non lambda code, > i.e. consider that 'return' or an implcit 'return' can be trasformed to a return null by the compiler. > > Void m() { > return; // the compiler generates return null; > } > > Void m() { } // the compiler generates return null; > > > On the positive side, it mix well with the switch expression proposed in the Pattern Matching JEP. > > Supplier supplier = > () -> switchexpr(someValue) { > case 0 -> System.out.println("foo"); > default -> { /* empty */ } > }; > > > regards, > R?mi > > [1] http://openjdk.java.net/jeps/302 From brian.goetz at oracle.com Sun Oct 8 21:54:37 2017 From: brian.goetz at oracle.com (Brian Goetz) Date: Sun, 8 Oct 2017 17:54:37 -0400 Subject: My lambda leftovers In-Reply-To: References: <721278228.2638224.1507288579761.JavaMail.zimbra@u-pem.fr> Message-ID: <2f1aef5c-5714-f4a0-86d7-9f0a6769a9ba@oracle.com> +1. On 10/6/2017 7:51 AM, Tagir Valeev wrote: > Hello! > > As for throw, I think it should just be converted to an expression, > probably of the same type as a null literal (thus throw statement will > become an expression statement). In this case it could be useful not > only in lambdas, like: > > return list.isEmpty() ? throw new NoSuchElementException() : list.get(0); > > I believe, it was discussed in context of pattern matching. > > With best regards, > Tagir Valeev. > > On Fri, Oct 6, 2017 at 6:16 PM, Remi Forax wrote: >> Hi all, >> The JEP 302 list some improvements but I think some are missing, obviously, it's up to debate :) >> >> So here is my list of left leftovers: >> - support throw statement as a lambda expression >> >> I think we have already discussed informally about this one. >> The compiler should allow to have a lambda expression that starts with throw. >> >> so a code like this will become valid >> merge(key, value, (_, _) -> throw new IllegalStateException("key " + key + " already present)); >> >> >> - allow void to be converted to Void (by returning null) >> >> This proposal is perhaps more controversial, currently there is no way to simply convert a lambda statement to a lambda expression. >> So a code like will compile >> >> R sync(T initial, Function fun) { >> synchronized(lock) { >> return fun.apply(initial); >> } >> } >> >> Consumer c = System.out::println; >> sync("foo", c::accept); // the compiler should generate a synthetic static method that returns null >> >> This proposal is problematic because: >> - it implicitly produces a null, which is a bad idea >> - if there are several overloads, a lambda statement can now match more methods so the compiler may reject code that was previously working or worst call another method that the one that was originally selected. >> >> >> The other question is should the conversion be extended to work with non lambda code, >> i.e. consider that 'return' or an implcit 'return' can be trasformed to a return null by the compiler. >> >> Void m() { >> return; // the compiler generates return null; >> } >> >> Void m() { } // the compiler generates return null; >> >> >> On the positive side, it mix well with the switch expression proposed in the Pattern Matching JEP. >> >> Supplier supplier = >> () -> switchexpr(someValue) { >> case 0 -> System.out.println("foo"); >> default -> { /* empty */ } >> }; >> >> >> regards, >> R?mi >> >> [1] http://openjdk.java.net/jeps/302 From maurizio.cimadamore at oracle.com Mon Oct 9 09:02:26 2017 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Mon, 9 Oct 2017 10:02:26 +0100 Subject: My lambda leftovers In-Reply-To: <2f1aef5c-5714-f4a0-86d7-9f0a6769a9ba@oracle.com> References: <721278228.2638224.1507288579761.JavaMail.zimbra@u-pem.fr> <2f1aef5c-5714-f4a0-86d7-9f0a6769a9ba@oracle.com> Message-ID: <63432c92-c74f-0c5d-1347-cfd334abca2f@oracle.com> While I sympathize with the proposal, I think making 'throw' an expression is trickier than it seems; in Java expression have types - if we make 'throw' an expression, then we must state what type does it have. In Scala the Nothing type is used for this purpose; Java doesn't have such a type. This is evident in cases like this: m(Z z) { ... } m(throw xyz) So, while I agree this would be a nice-to-have from an usability perspective, this feature has a cost w.r.t. type system - e.g. it's not a simple toggle flag on the parser. Maurizio On 08/10/17 22:54, Brian Goetz wrote: > +1. > > On 10/6/2017 7:51 AM, Tagir Valeev wrote: >> Hello! >> >> As for throw, I think it should just be converted to an expression, >> probably of the same type as a null literal (thus throw statement will >> become an expression statement). In this case it could be useful not >> only in lambdas, like: >> >> return list.isEmpty() ? throw new NoSuchElementException() : >> list.get(0); >> >> I believe, it was discussed in context of pattern matching. >> >> With best regards, >> Tagir Valeev. >> >> On Fri, Oct 6, 2017 at 6:16 PM, Remi Forax wrote: >>> Hi all, >>> The JEP 302 list some improvements but I think some are missing, >>> obviously, it's up to debate :) >>> >>> So here is my list of left leftovers: >>> - support throw statement as a lambda expression >>> >>> ?? I think we have already discussed informally about this one. >>> ?? The compiler should allow to have a lambda expression that starts >>> with throw. >>> >>> ?? so a code like this will become valid >>> ?? merge(key, value, (_, _) -> throw new IllegalStateException("key >>> " + key + " already present)); >>> >>> >>> - allow void to be converted to Void (by returning null) >>> >>> ?? This proposal is perhaps more controversial, currently there is >>> no way to simply convert a lambda statement to a lambda expression. >>> ?? So a code like will compile >>> >>> ??? R sync(T initial, Function fun) { >>> ???? synchronized(lock) { >>> ?????? return fun.apply(initial); >>> ???? } >>> ?? } >>> >>> ?? Consumer c = System.out::println; >>> ?? sync("foo", c::accept);???? // the compiler should generate a >>> synthetic static method that returns null >>> >>> ?? This proposal is problematic because: >>> ?? - it implicitly produces a null, which is a bad idea >>> ?? - if there are several overloads, a lambda statement can now >>> match more methods so the compiler may reject code that was >>> previously working or worst call another method that the one that >>> was originally selected. >>> >>> >>> ? The other question is should the conversion be extended to work >>> with non lambda code, >>> ? i.e. consider that 'return' or an implcit 'return' can be >>> trasformed to a return null by the compiler. >>> >>> ?? Void m() { >>> ???? return;???? // the compiler generates return null; >>> ?? } >>> >>> ?? Void m() { }? // the compiler generates return null; >>> >>> >>> ? On the positive side, it mix well with the switch expression >>> proposed in the Pattern Matching JEP. >>> >>> ?? Supplier supplier = >>> ?????? () -> switchexpr(someValue) { >>> ???????????????? case 0 -> System.out.println("foo"); >>> ???????????????? default -> { /* empty */ } >>> ???????????? }; >>> >>> >>> regards, >>> R?mi >>> >>> [1] http://openjdk.java.net/jeps/302 > From forax at univ-mlv.fr Mon Oct 9 09:32:26 2017 From: forax at univ-mlv.fr (forax at univ-mlv.fr) Date: Mon, 9 Oct 2017 11:32:26 +0200 (CEST) Subject: My lambda leftovers In-Reply-To: <63432c92-c74f-0c5d-1347-cfd334abca2f@oracle.com> References: <721278228.2638224.1507288579761.JavaMail.zimbra@u-pem.fr> <2f1aef5c-5714-f4a0-86d7-9f0a6769a9ba@oracle.com> <63432c92-c74f-0c5d-1347-cfd334abca2f@oracle.com> Message-ID: <895014927.173643.1507541546306.JavaMail.zimbra@u-pem.fr> There is plenty of types that are only know by the compiler, so i don't think it's a real issue. There is another issue { throw ...; } as now two possible representations in term of parser tree (the throw as statement or throw as exception + expression statement), given that the Tree is visible in term of API, that's why i have limited the proposal to throw inside a lambda. R?mi ----- Mail original ----- > De: "Maurizio Cimadamore" > ?: "Brian Goetz" , "Tagir Valeev" , "Remi Forax" > Cc: "amber-spec-experts" > Envoy?: Lundi 9 Octobre 2017 11:02:26 > Objet: Re: My lambda leftovers > While I sympathize with the proposal, I think making 'throw' an > expression is trickier than it seems; in Java expression have types - if > we make 'throw' an expression, then we must state what type does it > have. In Scala the Nothing type is used for this purpose; Java doesn't > have such a type. This is evident in cases like this: > > m(Z z) { ... } > > m(throw xyz) > > So, while I agree this would be a nice-to-have from an usability > perspective, this feature has a cost w.r.t. type system - e.g. it's not > a simple toggle flag on the parser. > > Maurizio > > > > On 08/10/17 22:54, Brian Goetz wrote: >> +1. >> >> On 10/6/2017 7:51 AM, Tagir Valeev wrote: >>> Hello! >>> >>> As for throw, I think it should just be converted to an expression, >>> probably of the same type as a null literal (thus throw statement will >>> become an expression statement). In this case it could be useful not >>> only in lambdas, like: >>> >>> return list.isEmpty() ? throw new NoSuchElementException() : >>> list.get(0); >>> >>> I believe, it was discussed in context of pattern matching. >>> >>> With best regards, >>> Tagir Valeev. >>> >>> On Fri, Oct 6, 2017 at 6:16 PM, Remi Forax wrote: >>>> Hi all, >>>> The JEP 302 list some improvements but I think some are missing, >>>> obviously, it's up to debate :) >>>> >>>> So here is my list of left leftovers: >>>> - support throw statement as a lambda expression >>>> >>>> ?? I think we have already discussed informally about this one. >>>> ?? The compiler should allow to have a lambda expression that starts >>>> with throw. >>>> >>>> ?? so a code like this will become valid >>>> ?? merge(key, value, (_, _) -> throw new IllegalStateException("key >>>> " + key + " already present)); >>>> >>>> >>>> - allow void to be converted to Void (by returning null) >>>> >>>> ?? This proposal is perhaps more controversial, currently there is >>>> no way to simply convert a lambda statement to a lambda expression. >>>> ?? So a code like will compile >>>> >>>> ??? R sync(T initial, Function fun) { >>>> ???? synchronized(lock) { >>>> ?????? return fun.apply(initial); >>>> ???? } >>>> ?? } >>>> >>>> ?? Consumer c = System.out::println; >>>> ?? sync("foo", c::accept);???? // the compiler should generate a >>>> synthetic static method that returns null >>>> >>>> ?? This proposal is problematic because: >>>> ?? - it implicitly produces a null, which is a bad idea >>>> ?? - if there are several overloads, a lambda statement can now >>>> match more methods so the compiler may reject code that was >>>> previously working or worst call another method that the one that >>>> was originally selected. >>>> >>>> >>>> ? The other question is should the conversion be extended to work >>>> with non lambda code, >>>> ? i.e. consider that 'return' or an implcit 'return' can be >>>> trasformed to a return null by the compiler. >>>> >>>> ?? Void m() { >>>> ???? return;???? // the compiler generates return null; >>>> ?? } >>>> >>>> ?? Void m() { }? // the compiler generates return null; >>>> >>>> >>>> ? On the positive side, it mix well with the switch expression >>>> proposed in the Pattern Matching JEP. >>>> >>>> ?? Supplier supplier = >>>> ?????? () -> switchexpr(someValue) { >>>> ???????????????? case 0 -> System.out.println("foo"); >>>> ???????????????? default -> { /* empty */ } >>>> ???????????? }; >>>> >>>> >>>> regards, >>>> R?mi >>>> >>>> [1] http://openjdk.java.net/jeps/302 From maurizio.cimadamore at oracle.com Mon Oct 9 10:38:58 2017 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Mon, 9 Oct 2017 11:38:58 +0100 Subject: My lambda leftovers In-Reply-To: <895014927.173643.1507541546306.JavaMail.zimbra@u-pem.fr> References: <721278228.2638224.1507288579761.JavaMail.zimbra@u-pem.fr> <2f1aef5c-5714-f4a0-86d7-9f0a6769a9ba@oracle.com> <63432c92-c74f-0c5d-1347-cfd334abca2f@oracle.com> <895014927.173643.1507541546306.JavaMail.zimbra@u-pem.fr> Message-ID: <1fb80670-5fc5-2ace-a109-d0375fef5605@oracle.com> On 09/10/17 10:32, forax at univ-mlv.fr wrote: > There is plenty of types that are only know by the compiler, so i don't think it's a real issue. Heh - until the compiler 'throws' them into your face with a diagnostic. Also: var x = throws xyz :-) > > There is another issue > { > throw ...; > } > as now two possible representations in term of parser tree (the throw as statement or throw as exception + expression statement), given that the Tree is visible in term of API, that's why i have limited the proposal to throw inside a lambda. Well, yes, the AST would change a bit, but the API exposing ASTs is compiler-specific (for method bodies at least) so it's not a big big big constraint. We're considering similar small tweaks for switch and patterns, where we're revamping the AST of a case so that the case expression will become a pattern (which can be a constant pattern in which case you get the old good 'case'). Maurizio > > R?mi > > ----- Mail original ----- >> De: "Maurizio Cimadamore" >> ?: "Brian Goetz" , "Tagir Valeev" , "Remi Forax" >> Cc: "amber-spec-experts" >> Envoy?: Lundi 9 Octobre 2017 11:02:26 >> Objet: Re: My lambda leftovers >> While I sympathize with the proposal, I think making 'throw' an >> expression is trickier than it seems; in Java expression have types - if >> we make 'throw' an expression, then we must state what type does it >> have. In Scala the Nothing type is used for this purpose; Java doesn't >> have such a type. This is evident in cases like this: >> >> m(Z z) { ... } >> >> m(throw xyz) >> >> So, while I agree this would be a nice-to-have from an usability >> perspective, this feature has a cost w.r.t. type system - e.g. it's not >> a simple toggle flag on the parser. >> >> Maurizio >> >> >> >> On 08/10/17 22:54, Brian Goetz wrote: >>> +1. >>> >>> On 10/6/2017 7:51 AM, Tagir Valeev wrote: >>>> Hello! >>>> >>>> As for throw, I think it should just be converted to an expression, >>>> probably of the same type as a null literal (thus throw statement will >>>> become an expression statement). In this case it could be useful not >>>> only in lambdas, like: >>>> >>>> return list.isEmpty() ? throw new NoSuchElementException() : >>>> list.get(0); >>>> >>>> I believe, it was discussed in context of pattern matching. >>>> >>>> With best regards, >>>> Tagir Valeev. >>>> >>>> On Fri, Oct 6, 2017 at 6:16 PM, Remi Forax wrote: >>>>> Hi all, >>>>> The JEP 302 list some improvements but I think some are missing, >>>>> obviously, it's up to debate :) >>>>> >>>>> So here is my list of left leftovers: >>>>> - support throw statement as a lambda expression >>>>> >>>>> ?? I think we have already discussed informally about this one. >>>>> ?? The compiler should allow to have a lambda expression that starts >>>>> with throw. >>>>> >>>>> ?? so a code like this will become valid >>>>> ?? merge(key, value, (_, _) -> throw new IllegalStateException("key >>>>> " + key + " already present)); >>>>> >>>>> >>>>> - allow void to be converted to Void (by returning null) >>>>> >>>>> ?? This proposal is perhaps more controversial, currently there is >>>>> no way to simply convert a lambda statement to a lambda expression. >>>>> ?? So a code like will compile >>>>> >>>>> ??? R sync(T initial, Function fun) { >>>>> ???? synchronized(lock) { >>>>> ?????? return fun.apply(initial); >>>>> ???? } >>>>> ?? } >>>>> >>>>> ?? Consumer c = System.out::println; >>>>> ?? sync("foo", c::accept);???? // the compiler should generate a >>>>> synthetic static method that returns null >>>>> >>>>> ?? This proposal is problematic because: >>>>> ?? - it implicitly produces a null, which is a bad idea >>>>> ?? - if there are several overloads, a lambda statement can now >>>>> match more methods so the compiler may reject code that was >>>>> previously working or worst call another method that the one that >>>>> was originally selected. >>>>> >>>>> >>>>> ? The other question is should the conversion be extended to work >>>>> with non lambda code, >>>>> ? i.e. consider that 'return' or an implcit 'return' can be >>>>> trasformed to a return null by the compiler. >>>>> >>>>> ?? Void m() { >>>>> ???? return;???? // the compiler generates return null; >>>>> ?? } >>>>> >>>>> ?? Void m() { }? // the compiler generates return null; >>>>> >>>>> >>>>> ? On the positive side, it mix well with the switch expression >>>>> proposed in the Pattern Matching JEP. >>>>> >>>>> ?? Supplier supplier = >>>>> ?????? () -> switchexpr(someValue) { >>>>> ???????????????? case 0 -> System.out.println("foo"); >>>>> ???????????????? default -> { /* empty */ } >>>>> ???????????? }; >>>>> >>>>> >>>>> regards, >>>>> R?mi >>>>> >>>>> [1] http://openjdk.java.net/jeps/302 From forax at univ-mlv.fr Mon Oct 9 14:08:41 2017 From: forax at univ-mlv.fr (forax at univ-mlv.fr) Date: Mon, 9 Oct 2017 16:08:41 +0200 (CEST) Subject: My lambda leftovers In-Reply-To: <1fb80670-5fc5-2ace-a109-d0375fef5605@oracle.com> References: <721278228.2638224.1507288579761.JavaMail.zimbra@u-pem.fr> <2f1aef5c-5714-f4a0-86d7-9f0a6769a9ba@oracle.com> <63432c92-c74f-0c5d-1347-cfd334abca2f@oracle.com> <895014927.173643.1507541546306.JavaMail.zimbra@u-pem.fr> <1fb80670-5fc5-2ace-a109-d0375fef5605@oracle.com> Message-ID: <2899928.348739.1507558121710.JavaMail.zimbra@u-pem.fr> ----- Mail original ----- > De: "Maurizio Cimadamore" > ?: forax at univ-mlv.fr > Cc: "Brian Goetz" , "Tagir Valeev" , "amber-spec-experts" > > Envoy?: Lundi 9 Octobre 2017 12:38:58 > Objet: Re: My lambda leftovers > On 09/10/17 10:32, forax at univ-mlv.fr wrote: >> There is plenty of types that are only know by the compiler, so i don't think >> it's a real issue. > Heh - until the compiler 'throws' them into your face with a diagnostic. > Also: > > var x = throw xyz > > :-) the other solution is to said that the typecheking of 'throw Foo' as an expression is equivalent to typecheck a call to a method V throwMethod() throws Foo. >> >> There is another issue >> { >> throw ...; >> } >> as now two possible representations in term of parser tree (the throw as >> statement or throw as exception + expression statement), given that the Tree is >> visible in term of API, that's why i have limited the proposal to throw inside >> a lambda. > Well, yes, the AST would change a bit, but the API exposing ASTs is > compiler-specific (for method bodies at least) so it's not a big big big > constraint. We're considering similar small tweaks for switch and > patterns, where we're revamping the AST of a case so that the case > expression will become a pattern (which can be a constant pattern in > which case you get the old good 'case'). yes, very true. > > Maurizio R?mi >> >> R?mi >> >> ----- Mail original ----- >>> De: "Maurizio Cimadamore" >>> ?: "Brian Goetz" , "Tagir Valeev" , >>> "Remi Forax" >>> Cc: "amber-spec-experts" >>> Envoy?: Lundi 9 Octobre 2017 11:02:26 >>> Objet: Re: My lambda leftovers >>> While I sympathize with the proposal, I think making 'throw' an >>> expression is trickier than it seems; in Java expression have types - if >>> we make 'throw' an expression, then we must state what type does it >>> have. In Scala the Nothing type is used for this purpose; Java doesn't >>> have such a type. This is evident in cases like this: >>> >>> m(Z z) { ... } >>> >>> m(throw xyz) >>> >>> So, while I agree this would be a nice-to-have from an usability >>> perspective, this feature has a cost w.r.t. type system - e.g. it's not >>> a simple toggle flag on the parser. >>> >>> Maurizio >>> >>> >>> >>> On 08/10/17 22:54, Brian Goetz wrote: >>>> +1. >>>> >>>> On 10/6/2017 7:51 AM, Tagir Valeev wrote: >>>>> Hello! >>>>> >>>>> As for throw, I think it should just be converted to an expression, >>>>> probably of the same type as a null literal (thus throw statement will >>>>> become an expression statement). In this case it could be useful not >>>>> only in lambdas, like: >>>>> >>>>> return list.isEmpty() ? throw new NoSuchElementException() : >>>>> list.get(0); >>>>> >>>>> I believe, it was discussed in context of pattern matching. >>>>> >>>>> With best regards, >>>>> Tagir Valeev. >>>>> >>>>> On Fri, Oct 6, 2017 at 6:16 PM, Remi Forax wrote: >>>>>> Hi all, >>>>>> The JEP 302 list some improvements but I think some are missing, >>>>>> obviously, it's up to debate :) >>>>>> >>>>>> So here is my list of left leftovers: >>>>>> - support throw statement as a lambda expression >>>>>> >>>>>> ?? I think we have already discussed informally about this one. >>>>>> ?? The compiler should allow to have a lambda expression that starts >>>>>> with throw. >>>>>> >>>>>> ?? so a code like this will become valid >>>>>> ?? merge(key, value, (_, _) -> throw new IllegalStateException("key >>>>>> " + key + " already present)); >>>>>> >>>>>> >>>>>> - allow void to be converted to Void (by returning null) >>>>>> >>>>>> ?? This proposal is perhaps more controversial, currently there is >>>>>> no way to simply convert a lambda statement to a lambda expression. >>>>>> ?? So a code like will compile >>>>>> >>>>>> ??? R sync(T initial, Function fun) { >>>>>> ???? synchronized(lock) { >>>>>> ?????? return fun.apply(initial); >>>>>> ???? } >>>>>> ?? } >>>>>> >>>>>> ?? Consumer c = System.out::println; >>>>>> ?? sync("foo", c::accept);???? // the compiler should generate a >>>>>> synthetic static method that returns null >>>>>> >>>>>> ?? This proposal is problematic because: >>>>>> ?? - it implicitly produces a null, which is a bad idea >>>>>> ?? - if there are several overloads, a lambda statement can now >>>>>> match more methods so the compiler may reject code that was >>>>>> previously working or worst call another method that the one that >>>>>> was originally selected. >>>>>> >>>>>> >>>>>> ? The other question is should the conversion be extended to work >>>>>> with non lambda code, >>>>>> ? i.e. consider that 'return' or an implcit 'return' can be >>>>>> trasformed to a return null by the compiler. >>>>>> >>>>>> ?? Void m() { >>>>>> ???? return;???? // the compiler generates return null; >>>>>> ?? } >>>>>> >>>>>> ?? Void m() { }? // the compiler generates return null; >>>>>> >>>>>> >>>>>> ? On the positive side, it mix well with the switch expression >>>>>> proposed in the Pattern Matching JEP. >>>>>> >>>>>> ?? Supplier supplier = >>>>>> ?????? () -> switchexpr(someValue) { >>>>>> ???????????????? case 0 -> System.out.println("foo"); >>>>>> ???????????????? default -> { /* empty */ } >>>>>> ???????????? }; >>>>>> >>>>>> >>>>>> regards, >>>>>> R?mi >>>>>> > >>>>> [1] http://openjdk.java.net/jeps/302 From brian.goetz at oracle.com Tue Oct 17 17:30:57 2017 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 17 Oct 2017 13:30:57 -0400 Subject: [patterns] primitive widening In-Reply-To: <317040581.7582921.1508059992025.JavaMail.zimbra@u-pem.fr> References: <84D17391-EE31-403A-8B0B-EF273E7F3D8F@oracle.com> <317040581.7582921.1508059992025.JavaMail.zimbra@u-pem.fr> Message-ID: <23d5a185-6004-5ec1-716d-d8e7e383d6aa@oracle.com> [ moving to amber-spec-experts ] There are a few ways we can interpret a primitive type test pattern (case int).? We could interpret them strictly, as Remi says, permitting only boxing adaptation when the target is a reference type; or we could interpret them more broadly, treating them as an assignability check (could I assign the target type to a variable of this type.) Assignment supports a combination of unboxing and widening; if we say ??? Short s = ... ??? int i = s this succeeds without a cast.? This seems like the correct spirit of "x matches int i"; could I assign, without explicit adaptation, the target to an int.? (On the other hand, assignment won't let us assign an Integer to a Short.) This has consequences for two forms of dead-code testing the compiler wants to do -- static applicability tests (where we reject nonsense combinations of target type and pattern) and dominance testing. Every pattern has a "bounding type": ?- For a constant pattern "case c", it is the type of c; ?- For a type test pattern "case T t", it is T; ?- For a destructuring pattern "case Foo(..)", it is Foo. Let's say: For a match "x matches P" or "switch (x) { case P: }", where X is the static type of x, P is considered inapplicable if a cast from X to B=bounding(P) would fail according to existing cast conversion rules, and should result in a compilation error. The above works when B and X are reference types; it needs to be further adjusted for the case when B is a primitive type; I think the refinement needed is we want to check for cast conversion from X to maybeBox(bounding(P)), where maybeBox is the identity on reference types and maps to the box type for primitives? Dominance testing is more complicated when it comes to primitives, but it means we have to treat int as dominating short (and Short).? Again, we can appeal to assignability; primitive type T dominates primitive Q (or Q's box) if Q can be assigned to T without a cast.? So int dominates short and Short. Bottom line: use cast conversion for "could this pattern match", use assignment conversion for dynamic type tests involving boxing, widening, and subtyping. On 10/15/2017 5:33 AM, Remi Forax wrote: > I do not think that a Short should matches a long if the pattern matching is defined as a suite of matches, the behavior will be weird. > By example with, > Object x = new Short(); > switch(x) { > case long l: ... > case short s: ... > } > it will be surprising that the first case matches. > > In my opinion, we should stick to > matches = instanceof + cast > the instanceof part is a plain old instanceof and the cast can be an unboxing but not a widening conversion > so with x an object > x matches long l <=> x instanceof Long + unbox Long > > With your example, > void test(Short x) { > assert(x matches long l); // compile error, because x instanceof Long is a compile error > } > > regards, > R?mi > > ----- Mail original ----- >> De: "John Rose" >> ?: "amber-dev" >> Envoy?: Dimanche 15 Octobre 2017 01:02:14 >> Objet: [patterns] primitive widening >> Interesting question: Should a "Short" box value >> match a "long" primitive? More generally, should >> pattern matching emulate assignment conversions? >> Including primitive widening conversions? >> >> Probably the answer is yes, under the theory that >> a pattern match digs through dynamic information to >> search for a *possible* assignment, and then (along >> that "match succeeded" path, is ready to make the >> assignment to a binding variable. >> >> void test(Short x) { >> long y = x; //OK >> longConsumer(x); //OK >> assert(x matches long); //OK?? >> } >> void longConsumer(long z) { } >> >> Does the prototype work that way? No, there is just an >> open-coded instanceof test of the wrapper type >> (makeTypeTest ? boxedTypeOrType). >> >> This is tricky to implement dynamically, but MH.invoke >> gets these details correct already, since it makes a >> dynamic emulation of (many of) Java's static rules for >> method argument conversion. >> >> ("Many of" means that the dynamic emulation is aware >> only of reified types, as if only raw types were present. >> Happily, the Core Reflection API also does the same >> emulation, although with different exceptions thrown.) >> >> These are the relevant routines from the MH runtime: >> sun.invoke.util.Wrapper::isConvertibleFrom >> sun.invoke.util.Wrapper::convert >> >> One good thing about this messy stuff: The widening >> primitive conversions (and narrowing ones, in the case >> of a cast) only come into play when the target type is >> really a primitive, not just a reference wrapping one. >> >> So we don't have to match a Short to a Long, just >> a Byte, Short, Character, Integer, Float, and Long to >> a primitive long (if the source type is a reference >> type that can contain any or all of the above). >> >> A factored runtime for pattern matching will be able >> to use the MH routines, if we decide that's the correct >> behavior. By "factored runtime" I hope for, of course, >> something with a metafactory for each switch and >> pattern. >> >> ? John From forax at univ-mlv.fr Tue Oct 31 08:47:50 2017 From: forax at univ-mlv.fr (Remi Forax) Date: Tue, 31 Oct 2017 09:47:50 +0100 (CET) Subject: Fix Parameter Runtime*ParameterAnnotations spec Message-ID: <803691474.399683.1509439670003.JavaMail.zimbra@u-pem.fr> [I've trouble to find what is the right list for the JVMS spec change describe below, so i apologize in advance for the spam] Hi all, the spec of the Runtime*ParameterAnnotations attribute [1], allow the number of parameter annotations to be different from the number of parameter from the method descriptor but it fails to provide a way to retrieve/compute the mapping between a parameter and a parameter annotation. So people try to guess and fail, here is by example the ASM bug when we tried to provide such mapping to our user [2]. We (the ASM team) believe the only way to fix that is to require that if the number of parameters from the descriptor and the number of parameter annotations doesn't match then compilers should also emit a Parameter attribute which already indicate if a parameter is synthetic or not. The Parameter attribute is not emitted by default by compilers because it will make the class files too fat, here we are proposing to only emit the Parameter attribute in the case where there are annotations on parameters and the method has synthetic parameters, so it should not be a problem. regards, R?mi [1] https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.18 [2] https://gitlab.ow2.org/asm/asm/issues/317788 From alex.buckley at oracle.com Tue Oct 31 19:11:26 2017 From: alex.buckley at oracle.com (Alex Buckley) Date: Tue, 31 Oct 2017 12:11:26 -0700 Subject: Fix Parameter Runtime*ParameterAnnotations spec In-Reply-To: <803691474.399683.1509439670003.JavaMail.zimbra@u-pem.fr> References: <803691474.399683.1509439670003.JavaMail.zimbra@u-pem.fr> Message-ID: <59F8CADE.9040106@oracle.com> On 10/31/2017 1:47 AM, Remi Forax wrote: > Hi all, the spec of the Runtime*ParameterAnnotations attribute [1], > allow the number of parameter annotations to be different from the > number of parameter from the method descriptor but it fails to > provide a way to retrieve/compute the mapping between a parameter and > a parameter annotation. > > So people try to guess and fail, here is by example the ASM bug when > we tried to provide such mapping to our user [2]. > > We (the ASM team) believe the only way to fix that is to require that > if the number of parameters from the descriptor and the number of > parameter annotations doesn't match then compilers should also emit a > Parameter attribute which already indicate if a parameter is > synthetic or not. I recognize that constructor parameters are a painful cause of discrepancy between the method descriptor and various attributes -- not just Runtime*ParameterAnnotations but also Signature (see the note "A method signature encoded by ..." in https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.9.1). However, the decision in JDK-8067975 was to loosen the JVMS' description so that it admitted the class files emitted by javac and ecj. If you want javac and ecj to emit something different than they do today, then your best bet is to write up a "State of the Parameters" page that shows the "interesting" programs, and what javac and ecj emit. Only then can suggestions like "Emit a MethodParameters attribute if ..." be evaluated. Alex