[swift-evolution] [Pitch] Exhaustive pattern matching forprotocols and classes

Xiaodi Wu xiaodi.wu at gmail.com
Wed May 25 13:09:15 CDT 2016


On Wed, May 25, 2016 at 12:49 PM, Matthew Johnson via swift-evolution <
swift-evolution at swift.org> wrote:

>
>
> Sent from my iPad
>
> On May 25, 2016, at 12:41 PM, Charlie Monroe <charlie at 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.
>
>
This doesn't at all solve the parent issue of switching exhaustively, but
switching over dynamicType distinguishes subclasses from base classes quite
adequately:

```
class Foo { }

class Bar : Foo { }

class Baz : Foo { }

let b = Bar()

switch b.dynamicType {
case let t where t == Foo.self:
    print("Foo!")
case let t where t == Bar.self:
    print("Bar!")
case let t where t == Baz.self:
    print("Baz!")
default:
    print("Boo...")
}
```



>
>
>
> 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 at 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 <davesweeris at mac.com>
> Sent: ‎24/‎05/‎2016 11:01 PM
> To: Austin Zheng <austinzheng at gmail.com>
> Cc: Leonardo Pessoa <me at lmpessoa.com>; swift-evolution
> <swift-evolution at 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 at 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 <me at 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 at 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 at 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 at swift.org
>> >> https://lists.swift.org/mailman/listinfo/swift-evolution
>> >
>> >
>> >
>> > _______________________________________________
>> > swift-evolution mailing list
>> > swift-evolution at swift.org
>> > https://lists.swift.org/mailman/listinfo/swift-evolution
>> >
>>
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
>
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160525/cd428b53/attachment.html>


More information about the swift-evolution mailing list