> Am 26.05.2016 um 17:29 schrieb Matthew Johnson <[email protected]>:
>
>>
>> On May 26, 2016, at 10:13 AM, Thorsten Seitz <[email protected]
>> <mailto:[email protected]>> wrote:
>>
>>>
>>> Am 26.05.2016 um 16:59 schrieb Matthew Johnson <[email protected]
>>> <mailto:[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.
>
> 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
>>>>>>> <[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