> Am 26.05.2016 um 16:59 schrieb Matthew Johnson <[email protected]>:
> 
>> 
>> On May 26, 2016, at 9:52 AM, Thorsten Seitz <[email protected] 
>> <mailto:[email protected]>> wrote:
>> 
>>> 
>>> Am 26.05.2016 um 15:40 schrieb Matthew Johnson <[email protected] 
>>> <mailto:[email protected]>>:
>>> 
>>> 
>>> 
>>> Sent from my iPad
>>> 
>>> On May 26, 2016, at 8:25 AM, Thorsten Seitz <[email protected] 
>>> <mailto:[email protected]>> 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.

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.


> 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...
But as you say that is a separate conversation and an easy fix would be to 
restrict `sealed` to protocols first.


> 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.

-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 
>>>>> <[email protected] <mailto:[email protected]>>:
>>>>> 
>>>>> 
>>>>> 
>>>>> Sent from my iPad
>>>>> 
>>>>> On May 25, 2016, at 12:41 PM, Charlie Monroe <[email protected] 
>>>>> <mailto:[email protected]>> 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 
>>>>>>>>>>> <[email protected] <mailto:[email protected]>> 
>>>>>>>>>>> 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:[email protected]>
>>>>>>>>>>> Sent: ‎24/‎05/‎2016 11:01 PM
>>>>>>>>>>> To: Austin Zheng <mailto:[email protected]>
>>>>>>>>>>> Cc: Leonardo Pessoa <mailto:[email protected]>; swift-evolution 
>>>>>>>>>>> <mailto:[email protected]>
>>>>>>>>>>> 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 
>>>>>>>>>>> <[email protected] <mailto:[email protected]>> 
>>>>>>>>>>> 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 
>>>>>>>>>>>> <[email protected] <mailto:[email protected]>> 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
>>>>>>>>>>>> <[email protected] <mailto:[email protected]>> 
>>>>>>>>>>>> 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
>>>>>>>>>>>> > <[email protected] <mailto:[email protected]>> 
>>>>>>>>>>>> > 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
>>>>>>>>>>>> >> [email protected] <mailto:[email protected]>
>>>>>>>>>>>> >> https://lists.swift.org/mailman/listinfo/swift-evolution 
>>>>>>>>>>>> >> <https://lists.swift.org/mailman/listinfo/swift-evolution>
>>>>>>>>>>>> >
>>>>>>>>>>>> >
>>>>>>>>>>>> >
>>>>>>>>>>>> > _______________________________________________
>>>>>>>>>>>> > swift-evolution mailing list
>>>>>>>>>>>> > [email protected] <mailto:[email protected]>
>>>>>>>>>>>> > https://lists.swift.org/mailman/listinfo/swift-evolution 
>>>>>>>>>>>> > <https://lists.swift.org/mailman/listinfo/swift-evolution>
>>>>>>>>>>>> >
>>>>>>>>>>>> 
>>>>>>>>>>>> _______________________________________________
>>>>>>>>>>>> swift-evolution mailing list
>>>>>>>>>>>> [email protected] <mailto:[email protected]>
>>>>>>>>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>>>>>>>>>>>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
>>>>>>>>>>> _______________________________________________
>>>>>>>>>>> swift-evolution mailing list
>>>>>>>>>>> [email protected] <mailto:[email protected]>
>>>>>>>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>>>>>>>>>>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
>>>>>>>>>> 
>>>>>>>>>> _______________________________________________
>>>>>>>>>> swift-evolution mailing list
>>>>>>>>>> [email protected] <mailto:[email protected]>
>>>>>>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>>>>>>>>>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
>>>>>> 
>>>>> _______________________________________________
>>>>> swift-evolution mailing list
>>>>> [email protected] <mailto:[email protected]>
>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>>>>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to