It should be possible to type a switch expression with void
forax at univ-mlv.fr
forax at univ-mlv.fr
Mon Sep 27 19:33:14 UTC 2021
----- Original Message -----
> From: "Tagir Valeev" <amaembo at gmail.com>
> To: "Remi Forax" <forax at univ-mlv.fr>
> Cc: "amber-spec-experts" <amber-spec-experts at 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 <forax at 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
More information about the amber-spec-observers
mailing list