----- Mail original -----
> De: "Brian Goetz" <brian.go...@oracle.com>
> À: "Remi Forax" <fo...@univ-mlv.fr>, "John Rose" <john.r.r...@oracle.com>
> Cc: "amber-spec-experts" <amber-spec-experts@openjdk.java.net>
> Envoyé: Mardi 11 Août 2020 15:57:36
> Objet: Re: Next up for patterns: type patterns in switch

>> - i don't think that framing the problem we have in term of null
>> haters / null friends is productive.
> 
> It may not be productive, but it is one of the elephants in the room.
> Some people sometimes take a hostile view of null ("We should prevent
> stream elements from being null!"), and, while this is often motivated
> by the best of intentions, it is a bias we need to be aware of.
> 

As far as i know, nobody in the EG has proposed that.

> 
>> There is a way to see a switch as a cascade of instanceof and to allow
>> null,
> 
> Herein lies danger, as both `switch` and `instanceof` have pre-existing,
> somewhat accidental null opinions.  But I agree that it is a good goal
> that switches and if-else chains of instanceof tests on the same target
> be refactorable to each other to the extent possible.
> 
>> This is almost the same semantics as the one you are proposing but
>> instead of the notion of totality, being the last case is enough to
>> accept null.
> 
> ... but what if the switch isn't total?  I can have
> 
>     switch (o) {
>         case Integer i: ...
>         case String s: ...
>         // no default, no total pattern
>     }
> 
> and it would be quite surprising to randomly shove nulls into the last case. 

It's not random, it's based on the fact that all cases but the last one are 
instanceof and the last one is a cast (see below)

> This would prevent the cases from being reordered even though
> they have no dominance ordering.  The reason the last case is special in
> the examples we've given so far is ... wait for it ... THEY ARE TOTAL.
> It would be a compiler error to have any more cases after them.  They
> are intrinsically catch-alls.

That why i have proposed first to syntactically make a difference using the 
syntax case String|null first but i'm sure someone can come with a better 
syntax.

Again, i understand why you think that a semantics based on the pattern being 
total or not make sense,
but you are only talking about the positive side and not the negative one.

The main drawback, being total is not a __local__ property.
So this is far worst that re-organizing two cases in the switch because as a 
user you have done something. A pattern can be total or not depending if 
someone change the return type of the method you are switching on (this methods 
can be in another module) or change the class hierarchy (again, the hierarchy 
can be defined in another module), the code stay exactly the same but the 
semantics is changed.

Adding an interface to a class should be harmless, but if this class is a case 
in a switch, this is changing the semantics of the switch. What can be worst in 
term of property ?
(again, C# doesn't have this issue because it is using "var" so the semantics 
is stable even if the type switched on change).

> 
>> I prefer this semantics, because it's local, the last case allows
>> null, it doesn't depends on the type of v or the relationship between
>> A and B.
> 
> This proposal seems entirely motivated by "let's have a really simple
> rule", rather than based on principles of what actually should happen in
> real programs or what programs should be expressible.  And, regardless
> of motivation, it is surely the wrong answer.

You can not in the same mail said that it's good goal "that switches and 
if-else chains of instanceof tests on the same target be refactorable to each 
other to the extent possible." and ends with "This proposal seems entirely 
motivated by ..., rather than based on principles of what actually should 
happen in real programs".

The semantics i'm proposing is based on real codes:
A switch like this
   switch (v) {
       case String s: A
       case Long l: B
       case Object o: C
   }
can be seen as
   if (v instanceof String s) {
    A
   } else if (v instanceof Long l) {
    B
   } else {
     var o = (Object) v;   // <--- cast here
     C
   }

It's a cut and paste from the mail you're answering.

Rémi


Reply via email to