> Am 26.05.2016 um 17:29 schrieb Matthew Johnson <matt...@anandabits.com>:
> 
>> 
>> On May 26, 2016, at 10:13 AM, Thorsten Seitz <tseit...@icloud.com 
>> <mailto:tseit...@icloud.com>> wrote:
>> 
>>> 
>>> Am 26.05.2016 um 16:59 schrieb Matthew Johnson <matt...@anandabits.com 
>>> <mailto:matt...@anandabits.com>>:
>>> 
>>>> 
>>>> On May 26, 2016, at 9:52 AM, Thorsten Seitz <tseit...@icloud.com 
>>>> <mailto:tseit...@icloud.com>> wrote:
>>>> 
>>>>> 
>>>>> Am 26.05.2016 um 15:40 schrieb Matthew Johnson <matt...@anandabits.com 
>>>>> <mailto:matt...@anandabits.com>>:
>>>>> 
>>>>> 
>>>>> 
>>>>> Sent from my iPad
>>>>> 
>>>>> On May 26, 2016, at 8:25 AM, Thorsten Seitz <tseit...@icloud.com 
>>>>> <mailto:tseit...@icloud.com>> wrote:
>>>>> 
>>>>>> Ceylon requires checks whether cases are disjoint, i.e. when one case 
>>>>>> contains a superclass of another case then this will be a type error 
>>>>>> „cases are not disjoint“.
>>>>>> 
>>>>>> FWIW: Ceylon requires classes with enumerated subclasses to be abstract. 
>>>>> 
>>>>> Interesting, thanks for mentioning this.  The abstract requirement is 
>>>>> what makes disjointedness at least partly possible (what if a subclass 
>>>>> has further descendants though?).  But it still only works for a single 
>>>>> level of inheritance:
>>>>> 
>>>>> sealed abstract class A {}
>>>>> class B : A {}
>>>>> class C : A {}
>>>>> class D : B {}
>>>>> class E : B {}
>>>>> 
>>>>> With a disjoint requirement I cannot ever match D and E because that 
>>>>> would not be exhaustive and I am prohibited from matching them along side 
>>>>> B which would be exhaustive but isn't disjoint.
>>>> 
>>>> Why?
>>>> 
>>>> switch a {
>>>> case C: …
>>>> case D: …
>>>> case E: …
>>>> }
>>>> 
>>>> is exhaustive because B has to be sealed as well (I would require this to 
>>>> be declared explicitly).
>>>> Abstractness seems not to be necessary for that IMO.
>>>> Either you match against B *or* against all its subclasses.
>>> 
>>> In my example `B` is not abstract.  `a` might have dynamic type of `B` 
>>> which would not match any of those cases.  
>> 
>> Ah, now I realize why the requirement for abstractness makes sense. Of 
>> course. Thanks for pointing that out!
>> 
>> 
>>> You didn’t mention that you have to make all non-leaf classes `abstract` 
>>> (or at least I didn’t understand that from what you wrote).  
>> 
>> The requirement in Ceylon is for classes with enumerated subclasses. B would 
>> have to declare D and E as enumerated subclasses (like I did for Child2 in 
>> the Ceylon example). In Ceylon this is not required, B could have normal 
>> subclasses D and E, but then you could not match against D or E at all 
>> because these would not be exhaustive (B might have other subclasses). The 
>> problem therefore is not stemming from disjointness requirements.
>> As soon as D and E are declared as disjoint (i.e. if B would be declared 
>> `sealed`) matching against them would be possible but B would have to be 
>> abstract.
> 
> In my example B is implicitly sealed because it has a sealed ancestor.  If it 
> weren’t you would be able to violate the sealed property of the ancestor by 
> inheriting from B.
> 
>> 
>> If I remove the enumerated subclasses from Child2 in the example I am 
>> allowed to make Child2 non-abstract. This of course results in the type 
>> error that the cases Child1 | Grandchild1 | Grandchild2 are not covering 
>> Parent anymore and I have to change the cases to match Child1 | Child2, 
>> removing the grandchildren matches because they are not disjoint with Child2.
> 
> Got it.  The enumerated subclasses are “partial sealing”.  They seal one 
> level of one branch of the inheritance hierarchy.  Interesting.  You can get 
> exhaustive matching without needing to seal the entire hierarchy.  I’m not 
> sure if I like this or not.  It is something to consider though, and it is 
> more flexible.
> 
>> 
>> 
>>> I don’t like a design that requires non-leaf classes to be abstract.  
>>> First, it would require introducing abstract classes into Swift, which is a 
>>> totally separate conversation and something I am not convinced is a good 
>>> idea.  
>> 
>> Well, I think abstract classes are something that is sorely missing in 
>> Swift! Very sorely missing…
> 
> I’ll keep my mind open about it.  My concern is that people will gravitate to 
> the familiar where protocols would be a better design.  I haven’t yet missed 
> abstract classes in Swift.
> 
>> But as you say that is a separate conversation and an easy fix would be to 
>> restrict `sealed` to protocols first.
> 
> Why do that?  We can have exhaustive switches without requiring abstract.

That’s right. So, exhaustiveness in case of non-abstract B would be given by 
matching either for B or for exactly B and all its subclasses, i.e.

Either

switch a {
case is C: ...
case is B: ...
}

or

switch a {
case is C: …
case isexactly B: …
case is D: …
case is E: …
}

In case of abstract B (in case this would be added to Swift one day) we would 
have:

switch a {
case is C: …
case is D: …
case is E: …
}


> 
>> 
>> 
>>> But it is also overly restrictive.  There are valid cases where you might 
>>> want an exhaustive switch for a sealed hierarchy that has concrete parent 
>>> classes.
>> 
>> In that case your suggestion of `isExactly` (or something shorter :-) would 
>> indeed be the solution.
> 
> Yep.  Any ideas for something more concise?

Maybe `iss` for „is strictly“? Probably too cryptic, though.

-Thorsten


> 
>> 
>> -Thorsten
>> 
>> 
>> 
>>> 
>>> If you want all non-leaf types to be abstract you should probably consider 
>>> using protocols in Swift.  
>>> 
>>>> 
>>>> Example in Ceylon:
>>>> abstract class Parent() of Child1 | Child2 {}
>>>> 
>>>> class Child1() extends Parent() {}
>>>> 
>>>> abstract class Child2() of Grandchild1 | Grandchild2 extends Parent() {}
>>>> 
>>>> class Grandchild1() extends Child2() {}
>>>> 
>>>> class Grandchild2() extends Child2() {}
>>>> 
>>>> void main() {
>>>>     Parent foo = Child1();
>>>> 
>>>>     switch (foo)
>>>>     case (is Child1) {
>>>>         print("Child1");
>>>>     }
>>>>     case (is Grandchild1) {
>>>>         print("Grandchild1");
>>>>     }
>>>>     case (is Grandchild2) {
>>>>         print("Grandchild2");
>>>>     }
>>>> }
>>>> 
>>>> -Thorsten
>>>> 
>>>>  
>>>>> 
>>>>> I don't think that solution is appropriate to Swift.  
>>>>> 
>>>>>> 
>>>>>> -Thorsten
>>>>>> 
>>>>>>  
>>>>>>> Am 25.05.2016 um 19:49 schrieb Matthew Johnson via swift-evolution 
>>>>>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>>:
>>>>>>> 
>>>>>>> 
>>>>>>> 
>>>>>>> Sent from my iPad
>>>>>>> 
>>>>>>> On May 25, 2016, at 12:41 PM, Charlie Monroe <char...@charliemonroe.net 
>>>>>>> <mailto:char...@charliemonroe.net>> wrote:
>>>>>>> 
>>>>>>>>> Got it.  You could also say it is safer because you can't have a 
>>>>>>>>> supertype case "swallow" a subtype value accidentally.  An "exact 
>>>>>>>>> type" cast would prevent this possibility.
>>>>>>>> 
>>>>>>>> This still can be an issue since you still need to do the switch in 
>>>>>>>> init(instance:), but it's just one place within the entire module, so 
>>>>>>>> it can be more easily managed...
>>>>>>> 
>>>>>>> Yes, agree.  That's why your enum is safer.  I think we do need an 
>>>>>>> exact type cast to prevent this problem.  'isExaclty' and 'asExactly' 
>>>>>>> seem are a bit verbose but are very clear.  I can't think of anything I 
>>>>>>> like that is more concise.
>>>>>>> 
>>>>>>>> 
>>>>>>>>> 
>>>>>>>>>> 
>>>>>>>>>> enum AnimalSubclasses {
>>>>>>>>>>      
>>>>>>>>>>      case Dog
>>>>>>>>>>      case Cat
>>>>>>>>>> 
>>>>>>>>>>      init(instance: Animal) {
>>>>>>>>>>              switch instance {
>>>>>>>>>>              case is Dog: self = .Dog
>>>>>>>>>>              case is Cat: self = .Cat
>>>>>>>>>>              default: fatalError("Unhandled instance \(instance)!")
>>>>>>>>>>      }
>>>>>>>>>> 
>>>>>>>>>> }
>>>>>>>>>> 
>>>>>>>>>>> One thing I have considered that might also be worth introducing is 
>>>>>>>>>>> an exact match cast.  This would prevent the possibility of putting 
>>>>>>>>>>> a superclass case first and having it “steal” subclasses which were 
>>>>>>>>>>> intended to be covered by a case later in the switch.  If we 
>>>>>>>>>>> introduce exact match you would be able to write a switch that must 
>>>>>>>>>>> always cover every concrete type, including all subclasses.  
>>>>>>>>>>> 
>>>>>>>>>>>> 
>>>>>>>>>>>> Charlie
>>>>>>>>>>>> 
>>>>>>>>>>>> 
>>>>>>>>>>>>> On May 25, 2016, at 4:41 AM, Leonardo Pessoa via swift-evolution 
>>>>>>>>>>>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> 
>>>>>>>>>>>>> wrote:
>>>>>>>>>>>>> 
>>>>>>>>>>>>> Limiting the amount of subclasses is not really a good idea as 
>>>>>>>>>>>>> you would need to introduce another mechanism in the language 
>>>>>>>>>>>>> while the proposed feature requires much less. And you're 
>>>>>>>>>>>>> thinking only about the restrictive set (internal and private) 
>>>>>>>>>>>>> and forgetting the more open end (public). Why is it so bad for 
>>>>>>>>>>>>> this proposal to support requiring the default case? If its 
>>>>>>>>>>>>> possible for the compiler to discover you covered all possible 
>>>>>>>>>>>>> cases it would be fine not having default but IMHO in most cases 
>>>>>>>>>>>>> it will find out there are more not explicitly covered.
>>>>>>>>>>>>> From: David Sweeris <mailto:daveswee...@mac.com>
>>>>>>>>>>>>> Sent: ‎24/‎05/‎2016 11:01 PM
>>>>>>>>>>>>> To: Austin Zheng <mailto:austinzh...@gmail.com>
>>>>>>>>>>>>> Cc: Leonardo Pessoa <mailto:m...@lmpessoa.com>; swift-evolution 
>>>>>>>>>>>>> <mailto:swift-evolution@swift.org>
>>>>>>>>>>>>> Subject: Re: [swift-evolution] [Pitch] Exhaustive pattern 
>>>>>>>>>>>>> matching forprotocols and classes
>>>>>>>>>>>>> 
>>>>>>>>>>>>> Or if there was a way to declare that a class/protocol can only 
>>>>>>>>>>>>> have a defined set of subclasses/conforming types.
>>>>>>>>>>>>> 
>>>>>>>>>>>>> Sent from my iPhone
>>>>>>>>>>>>> 
>>>>>>>>>>>>> On May 24, 2016, at 15:35, Austin Zheng via swift-evolution 
>>>>>>>>>>>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> 
>>>>>>>>>>>>> wrote:
>>>>>>>>>>>>> 
>>>>>>>>>>>>>> If you pattern match on a type that is declared internal or 
>>>>>>>>>>>>>> private, it is impossible for the compiler to not have an 
>>>>>>>>>>>>>> exhaustive list of subclasses that it can check against.
>>>>>>>>>>>>>> 
>>>>>>>>>>>>>> Austin
>>>>>>>>>>>>>> 
>>>>>>>>>>>>>> On Tue, May 24, 2016 at 1:29 PM, Leonardo Pessoa 
>>>>>>>>>>>>>> <m...@lmpessoa.com <mailto:m...@lmpessoa.com>> wrote:
>>>>>>>>>>>>>> I like this but I think it would be a lot hard to ensure you 
>>>>>>>>>>>>>> have all
>>>>>>>>>>>>>> subclasses covered. Think of frameworks that could provide many
>>>>>>>>>>>>>> unsealed classes. You could also have an object that would have 
>>>>>>>>>>>>>> to
>>>>>>>>>>>>>> handle a large subtree (NSObject?) and the order in which the 
>>>>>>>>>>>>>> cases
>>>>>>>>>>>>>> are evaluated would matter just as in exception handling in 
>>>>>>>>>>>>>> languages
>>>>>>>>>>>>>> such as Java (or require some evaluation from the compiler to 
>>>>>>>>>>>>>> raise
>>>>>>>>>>>>>> warnings). I'm +1 for this but these should be open-ended like 
>>>>>>>>>>>>>> strings
>>>>>>>>>>>>>> and require the default case.
>>>>>>>>>>>>>> 
>>>>>>>>>>>>>> On 24 May 2016 at 17:08, Austin Zheng via swift-evolution
>>>>>>>>>>>>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> 
>>>>>>>>>>>>>> wrote:
>>>>>>>>>>>>>> > I have been hoping for the exhaustive pattern matching feature 
>>>>>>>>>>>>>> > for a while
>>>>>>>>>>>>>> > now, and would love to see a proposal.
>>>>>>>>>>>>>> >
>>>>>>>>>>>>>> > Austin
>>>>>>>>>>>>>> >
>>>>>>>>>>>>>> > On Tue, May 24, 2016 at 1:01 PM, Matthew Johnson via 
>>>>>>>>>>>>>> > swift-evolution
>>>>>>>>>>>>>> > <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> 
>>>>>>>>>>>>>> > wrote:
>>>>>>>>>>>>>> >>
>>>>>>>>>>>>>> >> Swift currently requires a default pattern matching clause 
>>>>>>>>>>>>>> >> when you switch
>>>>>>>>>>>>>> >> on an existential or a non-final class even if the protocol 
>>>>>>>>>>>>>> >> or class is
>>>>>>>>>>>>>> >> non-public and all cases are covered.  It would be really 
>>>>>>>>>>>>>> >> nice if the
>>>>>>>>>>>>>> >> default clause were not necessary in this case.  The compiler 
>>>>>>>>>>>>>> >> has the
>>>>>>>>>>>>>> >> necessary information to prove exhaustiveness.
>>>>>>>>>>>>>> >>
>>>>>>>>>>>>>> >> Related to this is the idea of introducing something like a 
>>>>>>>>>>>>>> >> `sealed`
>>>>>>>>>>>>>> >> modifier that could be applied to public protocols and 
>>>>>>>>>>>>>> >> classes.  The
>>>>>>>>>>>>>> >> protocol or class would be visible when the module is 
>>>>>>>>>>>>>> >> imported, but
>>>>>>>>>>>>>> >> conformances or subclasses outside the declaring module would 
>>>>>>>>>>>>>> >> be prohibited.
>>>>>>>>>>>>>> >> Internal and private protocols and classes would implicitly 
>>>>>>>>>>>>>> >> be sealed since
>>>>>>>>>>>>>> >> they are not visible outside the module.  Any protocols that 
>>>>>>>>>>>>>> >> inherit from a
>>>>>>>>>>>>>> >> sealed protocol or classes that inherit from a sealed class 
>>>>>>>>>>>>>> >> would also be
>>>>>>>>>>>>>> >> implicitly sealed (if we didn’t do this the sealing of the 
>>>>>>>>>>>>>> >> superprotocol /
>>>>>>>>>>>>>> >> superclass could be violated by conforming to or inheriting 
>>>>>>>>>>>>>> >> from a
>>>>>>>>>>>>>> >> subprotocol / subclass).
>>>>>>>>>>>>>> >>
>>>>>>>>>>>>>> >> Here are examples that I would like to see be valid:
>>>>>>>>>>>>>> >>
>>>>>>>>>>>>>> >> protocol P {}
>>>>>>>>>>>>>> >> // alternatively public sealed protocol P {}
>>>>>>>>>>>>>> >> struct P1: P {}
>>>>>>>>>>>>>> >> struct P2: P {}
>>>>>>>>>>>>>> >>
>>>>>>>>>>>>>> >> func p(p: P) -> Int {
>>>>>>>>>>>>>> >>     switch p {
>>>>>>>>>>>>>> >>     case is P1: return 1 // alternatively an `as` cast
>>>>>>>>>>>>>> >>     case is P2: return 2 // alternatively an `as` cast
>>>>>>>>>>>>>> >>     }
>>>>>>>>>>>>>> >> }
>>>>>>>>>>>>>> >>
>>>>>>>>>>>>>> >> class C {}
>>>>>>>>>>>>>> >> // alternatively public sealed class C {}
>>>>>>>>>>>>>> >> class C1: C {}
>>>>>>>>>>>>>> >> class C2: C {}
>>>>>>>>>>>>>> >>
>>>>>>>>>>>>>> >> func c(c: C) -> Int {
>>>>>>>>>>>>>> >>     switch c {
>>>>>>>>>>>>>> >>     case is C1: return 1 // alternatively an `as` cast
>>>>>>>>>>>>>> >>     case is C2: return 2 // alternatively an `as` cast
>>>>>>>>>>>>>> >>     case is C: return 0   // alternatively an `as` cast
>>>>>>>>>>>>>> >>     }
>>>>>>>>>>>>>> >> }
>>>>>>>>>>>>>> >>
>>>>>>>>>>>>>> >> I am wondering if this is something the community is 
>>>>>>>>>>>>>> >> interested in.  If
>>>>>>>>>>>>>> >> so, I am wondering if this is something that might be 
>>>>>>>>>>>>>> >> possible in the Swift
>>>>>>>>>>>>>> >> 3 timeframe (maybe just for private and internal protocols 
>>>>>>>>>>>>>> >> and classes) or
>>>>>>>>>>>>>> >> if it should wait for Swift 4 (this is likely the case).
>>>>>>>>>>>>>> >>
>>>>>>>>>>>>>> >> -Matthew
>>>>>>>>>>>>>> >> _______________________________________________
>>>>>>>>>>>>>> >> swift-evolution mailing list
>>>>>>>>>>>>>> >> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
>>>>>>>>>>>>>> >> https://lists.swift.org/mailman/listinfo/swift-evolution 
>>>>>>>>>>>>>> >> <https://lists.swift.org/mailman/listinfo/swift-evolution>
>>>>>>>>>>>>>> >
>>>>>>>>>>>>>> >
>>>>>>>>>>>>>> >
>>>>>>>>>>>>>> > _______________________________________________
>>>>>>>>>>>>>> > swift-evolution mailing list
>>>>>>>>>>>>>> > swift-evolution@swift.org <mailto:swift-evolution@swift.org>
>>>>>>>>>>>>>> > https://lists.swift.org/mailman/listinfo/swift-evolution 
>>>>>>>>>>>>>> > <https://lists.swift.org/mailman/listinfo/swift-evolution>
>>>>>>>>>>>>>> >
>>>>>>>>>>>>>> 
>>>>>>>>>>>>>> _______________________________________________
>>>>>>>>>>>>>> swift-evolution mailing list
>>>>>>>>>>>>>> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
>>>>>>>>>>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>>>>>>>>>>>>>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
>>>>>>>>>>>>> _______________________________________________
>>>>>>>>>>>>> swift-evolution mailing list
>>>>>>>>>>>>> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
>>>>>>>>>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>>>>>>>>>>>>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
>>>>>>>>>>>> 
>>>>>>>>>>>> _______________________________________________
>>>>>>>>>>>> swift-evolution mailing list
>>>>>>>>>>>> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
>>>>>>>>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>>>>>>>>>>>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
>>>>>>>> 
>>>>>>> _______________________________________________
>>>>>>> swift-evolution mailing list
>>>>>>> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
>>>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>>>>>>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to