----- Original Message ----- > From: "Tagir Valeev" <amae...@gmail.com> > To: "Remi Forax" <fo...@univ-mlv.fr> > Cc: "amber-spec-experts" <amber-spec-experts@openjdk.java.net> > Sent: Lundi 27 Septembre 2021 06:38:14 > Subject: Re: It should be possible to type a switch expression with void
> If you expect this to be changed, the same would be expected e.g. from ?: > expression. Why ? Both the lambda expression and the switch uses the arrow syntax but the associated semantics is different. A lambda allow void expression. A switch does not allow void expression. It feels arbitrary and obvisouly does not work when you combine the two syntax. ?: does not use the arrow syntax so it does not have to be changed the same way, it does not have to accept a yield. > This also would create some kind of confusion: the > switch expression cannot be inside the expression statement, but the > expression statement is mostly associated with void-type expression. Nobody knows what the expression statement is apart if you know the Java grammar. I don't think it's a real issue. > > Btw, there's another place where void-expression is allowed: update > clause in for statement: > for(int i=0; i<10; switch(i) {case 1 -> > System.out.println(i++);default -> i++;}) {} > Should this work? again, no arrow used here. > > Your example assumes more changes to the switch expression, not just > the 'void' type. You also assume that the block can omit the yield > statement, and in this case the resulting type of the corresponding > rule is considered to be 'void'. Also, what will be the resulting type > of switch expression in case if different branches have different > void-ness? E.g.: > > (i, consumer) -> switch(i) { > case A a -> consumer.accept(a); // void branch > case B b -> myList.add(b); // boolean branch > } > > I don't think we already have result type rules for void & boolean > (JLS 15.28.1). Should we set the resulting type as 'void'? This might > be confusing and error-prone. E.g., I have two method overloads (think > of ExecutorService.submit(Runnable) and > ExecutorService.submit(Callable)). I may assume that the result is > used but in fact it's not because I forget yield in one of the > branches, so the rule type is set to void, this changes the type of > the whole switch expression to the 'void', so the results of all other > branches are ignored, lambda becomes void-compatible and we resolve to > submit(Runnable) instead of submit(Callable). Sounds not very good. The problem with submit(Runnable) vs submit(Callable) is already a problem with a lambda, we have a warning if someone write such overloads, sadly the methods Executor.submit() predates this warning which was introduced in 8. Apart that corner case, yes, it will make the error reporting a little harder, if a switch expression is typed void and the value is stored into a variable, the error can be either there is a missing yield in a case or the value should not be stored in a local variable. But it's very similar to the way a lambda works, if a lambda call a method that return void but the functional interface does not accept void, the error can be either that the body is wrong or that the functional interface type is wrong. > > With best regards, > Tagir Valeev. regards, Rémi > > On Mon, Sep 27, 2021 at 2:11 AM Remi Forax <fo...@univ-mlv.fr> wrote: >> >> There is a bad interaction between a lambda and a switch expression, >> a lambda allows its expression to be typed void but a switch expression can >> not >> be typed void, >> so the following code does not compile >> >> sealed interface I permits A, B {} >> record A() {} >> record B() {} >> >> public Optional<A> findOneA(List<I> list) { >> return list.stream() >> .<A>mapMulti((i, consumer) -> switch(i) { >> case A a -> consumer.accept(a); >> case B b -> {} >> }) >> .findFirst(); >> } >> >> This bug occurs for with any methods that takes a Consumer has parameter (so >> stream.forEach/peek, Iterator.forEachRemaining etc). >> >> The workaound is to add a pair of curly braces around the switch to >> transform it >> to a switch statement. >> >> For me, it should be possible to have a switch expression typed void. This >> is a >> backward compatible change given that the code does not compile otherwise. >> >> regards, > > Rémi