[Pitch] Exhaustive pattern matching for protocols and classes


(Matthew Johnson) #1

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


(Austin Zheng) #2

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> 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
https://lists.swift.org/mailman/listinfo/swift-evolution


(Leonardo Pessoa) #3

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> 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> 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
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Austin Zheng) #4

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@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> 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> 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
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>


(David Sweeris) #5

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> 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@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> 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> 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
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Matthew Johnson) #6

Or if there was a way to declare that a class/protocol can only have a defined set of subclasses/conforming types.

Yes, that is why I suggest introducing 'sealed'.

···

Sent from my iPad

On May 24, 2016, at 9:01 PM, David Sweeris via swift-evolution <swift-evolution@swift.org> wrote:

Sent from my iPhone

On May 24, 2016, at 15:35, Austin Zheng via swift-evolution <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 <me@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> 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> 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
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Leonardo Pessoa) #7

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.

···

-----Original Message-----
From: "David Sweeris" <davesweeris@mac.com>
Sent: ‎24/‎05/‎2016 11:01 PM
To: "Austin Zheng" <austinzheng@gmail.com>
Cc: "Leonardo Pessoa" <me@lmpessoa.com>; "swift-evolution" <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> 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@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> 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> 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
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Thorsten Seitz) #8

Ceylon uses the following syntax for stating that a class has a finite set of subclasses:

class C of C1 | C2 {...}

where `|` is the type union operator. Swift could use a simple comma separated list instead after the `or`. The advantage over sealed+private/internal would be thatnthe class or protocol could be public as well.

-Thorsten

···

Am 25.05.2016 um 04:01 schrieb David Sweeris via swift-evolution <swift-evolution@swift.org>:

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> 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@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> 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> 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
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Charlie Monroe) #9

There are legit cases where you want to be able to subclass the class within a module (framework), but you don't want others to subclass it out of the framework in order to provide some integrity. This is usually done nowadays (on many places within Apple's frameworks) by an assertion in init.

It is very similar to declaring public internal(set) var - but with a class and subclassing instead of modifying the contents of a var.

And without it, you can't do this efficiently - the default case is dangerous if you have a variable that returns non-nil value depending on the class - the default case usually has fatalError() inside - forgetting to add the clause for a new class won't be discovered until runtime.

I personally bypass this currently by having an enum of classes defined with an initializer init(instance:) and then switch by the enum, which is safer than switch by type - but it's extra work.

Charlie

···

On May 25, 2016, at 4:41 AM, Leonardo Pessoa via swift-evolution <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:davesweeris@mac.com>
Sent: ‎24/‎05/‎2016 11:01 PM
To: Austin Zheng <mailto:austinzheng@gmail.com>
Cc: Leonardo Pessoa <mailto:me@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 <me@lmpessoa.com <mailto:me@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
>
>
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
> 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

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Thorsten Seitz) #10

Just realized that Matthew did introduce `sealed` exactly to enable this for public types. That's fine with me!

-Thorsten

···

Am 25.05.2016 um 18:11 schrieb Thorsten Seitz via swift-evolution <swift-evolution@swift.org>:

Ceylon uses the following syntax for stating that a class has a finite set of subclasses:

class C of C1 | C2 {...}

where `|` is the type union operator. Swift could use a simple comma separated list instead after the `or`. The advantage over sealed+private/internal would be thatnthe class or protocol could be public as well.

-Thorsten

Am 25.05.2016 um 04:01 schrieb David Sweeris via swift-evolution <swift-evolution@swift.org>:

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> 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@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> 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> 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
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Matthew Johnson) #11

There are legit cases where you want to be able to subclass the class within a module (framework), but you don't want others to subclass it out of the framework in order to provide some integrity. This is usually done nowadays (on many places within Apple's frameworks) by an assertion in init.

It is very similar to declaring public internal(set) var - but with a class and subclassing instead of modifying the contents of a var.

And without it, you can't do this efficiently - the default case is dangerous if you have a variable that returns non-nil value depending on the class - the default case usually has fatalError() inside - forgetting to add the clause for a new class won't be discovered until runtime.

+1 about not being notified of missing cases if you add a new conforming type or subclass. This is a big part of the reason for doing tis.

I personally bypass this currently by having an enum of classes defined with an initializer init(instance:) and then switch by the enum, which is safer than switch by type - but it's extra work.

Do you mean safer because you con’t forget to add new cases? Or just safer in general?

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.

···

On May 25, 2016, at 12:38 AM, Charlie Monroe via swift-evolution <swift-evolution@swift.org> wrote:

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:davesweeris@mac.com>
Sent: ‎24/‎05/‎2016 11:01 PM
To: Austin Zheng <mailto:austinzheng@gmail.com>
Cc: Leonardo Pessoa <mailto:me@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 <me@lmpessoa.com <mailto:me@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
>
>
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
> 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

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Matthew Johnson) #12

Just realized that Matthew did introduce `sealed` exactly to enable this for public types. That's fine with me!

Yeah, and it doesn't require repeating the subclass all in one place which I think is a better fit for Swift.

I'm thinking the "exact type" cast (not in my original post) should also be a part of the solution. What do you think of that?

···

Sent from my iPad

On May 25, 2016, at 11:18 AM, Thorsten Seitz via swift-evolution <swift-evolution@swift.org> wrote:

-Thorsten

Am 25.05.2016 um 18:11 schrieb Thorsten Seitz via swift-evolution <swift-evolution@swift.org>:

Ceylon uses the following syntax for stating that a class has a finite set of subclasses:

class C of C1 | C2 {...}

where `|` is the type union operator. Swift could use a simple comma separated list instead after the `or`. The advantage over sealed+private/internal would be thatnthe class or protocol could be public as well.

-Thorsten

Am 25.05.2016 um 04:01 schrieb David Sweeris via swift-evolution <swift-evolution@swift.org>:

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> 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@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> 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> 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
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Matthew Johnson) #13

I like the idea of sealed types but I think much better is Ceylon's concept of previously declaring the many subclasses that are going to exist both because I can have a bunch of public classes in a framework and restrict their subclasses and because there are threads in this group discussing the idea of a union type (perhaps both ideas could benefit from one another).

I think there are reasonable arguments both for and against forcing the programmer to declare all subclasses in one location. The argument for it is that it provides documentation value by listing all possible cases in the same place. The argument against it is that this could get annoying as you add subclasses inside the module and the compiler will tell you when you miss a case in your switches anyway.

Another idea could be to add a single simple keyword to the root class (could even be sealed but I don't think it grabs this concept) to declare all its subclasses must exist within the same module. That would restrict the number of subclasses to the compiler without requiring us to revisit the root class each time we need to create a subclass and would still allow for every subclass to be public.

Sealed wouldn't be a good idea because the root class would still enable subclassing and it would be ideal that the switch could only work with these "sealed" types.

I proposed 'sealed' for this using the definition we have seen previously on the list - closed to inheritance outside the module. It doesn't mean 'final'.

+1 for enabling this for protocols too.

Just a few issues:
- here we're considering having subclasses of subclasses, or not?

Yes, as long as they're within the same module as the 'sealed' type.

-what about public protocols being adopted outside the module, should we just ignore them or completely forbid the adoption?

The ability to have 'public sealed' is the only reason to have 'sealed' at all. 'private' and 'internal' are implicitly 'sealed' by lack of external visibility. If your users need to be able to conform to your protocol you wouldn't be able to make it 'sealed' and would have to include the default clause in a switch statement. 'sealed' is for times where your design requires a fixed set of conformances that are all packed together in the same module as the protocol, but the protocol must be visible publicly.

···

Sent from my iPad

On May 25, 2016, at 12:04 PM, Leonardo Pessoa via swift-evolution <swift-evolution@swift.org> wrote:

From: Thorsten Seitz via swift-evolution
Sent: ‎25/‎05/‎2016 01:18 PM
To: Thorsten Seitz
Cc: swift-evolution
Subject: Re: [swift-evolution] [Pitch] Exhaustive pattern matching forprotocols and classes

Just realized that Matthew did introduce `sealed` exactly to enable this for public types. That's fine with me!

-Thorsten

Am 25.05.2016 um 18:11 schrieb Thorsten Seitz via swift-evolution <swift-evolution@swift.org>:

Ceylon uses the following syntax for stating that a class has a finite set of subclasses:

class C of C1 | C2 {...}

where `|` is the type union operator. Swift could use a simple comma separated list instead after the `or`. The advantage over sealed+private/internal would be thatnthe class or protocol could be public as well.

-Thorsten

Am 25.05.2016 um 04:01 schrieb David Sweeris via swift-evolution <swift-evolution@swift.org>:

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> 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@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> 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> 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
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Matthew Johnson) #14

I like the idea of sealed types but I think much better is Ceylon's concept of previously declaring the many subclasses that are going to exist both because I can have a bunch of public classes in a framework and restrict their subclasses and because there are threads in this group discussing the idea of a union type (perhaps both ideas could benefit from one another).

I forgot to mention this in my last reply. What I am proposing allows sealed classes to be viewed as similar to nominal sum types. This is like Scala's case classes.

Ceylon's unions are structural sum types (the sum type analogue of a Tuple, which is a structural product type). I really want to see these as well (I recently ran into a use case where they are far superior to what we can do today). But they are not the same as sealed classes and protocols.

···

Sent from my iPad

On May 25, 2016, at 12:04 PM, Leonardo Pessoa via swift-evolution <swift-evolution@swift.org> wrote:

Another idea could be to add a single simple keyword to the root class (could even be sealed but I don't think it grabs this concept) to declare all its subclasses must exist within the same module. That would restrict the number of subclasses to the compiler without requiring us to revisit the root class each time we need to create a subclass and would still allow for every subclass to be public.

Sealed wouldn't be a good idea because the root class would still enable subclassing and it would be ideal that the switch could only work with these "sealed" types.

+1 for enabling this for protocols too.

Just a few issues:
- here we're considering having subclasses of subclasses, or not?
-what about public protocols being adopted outside the module, should we just ignore them or completely forbid the adoption?

From: Thorsten Seitz via swift-evolution
Sent: ‎25/‎05/‎2016 01:18 PM
To: Thorsten Seitz
Cc: swift-evolution
Subject: Re: [swift-evolution] [Pitch] Exhaustive pattern matching forprotocols and classes

Just realized that Matthew did introduce `sealed` exactly to enable this for public types. That's fine with me!

-Thorsten

Am 25.05.2016 um 18:11 schrieb Thorsten Seitz via swift-evolution <swift-evolution@swift.org>:

Ceylon uses the following syntax for stating that a class has a finite set of subclasses:

class C of C1 | C2 {...}

where `|` is the type union operator. Swift could use a simple comma separated list instead after the `or`. The advantage over sealed+private/internal would be thatnthe class or protocol could be public as well.

-Thorsten

Am 25.05.2016 um 04:01 schrieb David Sweeris via swift-evolution <swift-evolution@swift.org>:

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> 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@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> 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> 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
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Leonardo Pessoa) #15

I like the idea of sealed types but I think much better is Ceylon's concept of previously declaring the many subclasses that are going to exist both because I can have a bunch of public classes in a framework and restrict their subclasses and because there are threads in this group discussing the idea of a union type (perhaps both ideas could benefit from one another).

Another idea could be to add a single simple keyword to the root class (could even be sealed but I don't think it grabs this concept) to declare all its subclasses must exist within the same module. That would restrict the number of subclasses to the compiler without requiring us to revisit the root class each time we need to create a subclass and would still allow for every subclass to be public.

Sealed wouldn't be a good idea because the root class would still enable subclassing and it would be ideal that the switch could only work with these "sealed" types.

+1 for enabling this for protocols too.

Just a few issues:
- here we're considering having subclasses of subclasses, or not?
-what about public protocols being adopted outside the module, should we just ignore them or completely forbid the adoption?

···

-----Original Message-----
From: "Thorsten Seitz via swift-evolution" <swift-evolution@swift.org>
Sent: ‎25/‎05/‎2016 01:18 PM
To: "Thorsten Seitz" <tseitz42@icloud.com>
Cc: "swift-evolution" <swift-evolution@swift.org>
Subject: Re: [swift-evolution] [Pitch] Exhaustive pattern matching forprotocols and classes

Just realized that Matthew did introduce `sealed` exactly to enable this for public types. That's fine with me!

-Thorsten

Am 25.05.2016 um 18:11 schrieb Thorsten Seitz via swift-evolution <swift-evolution@swift.org>:

Ceylon uses the following syntax for stating that a class has a finite set of subclasses:

class C of C1 | C2 {...}

where `|` is the type union operator. Swift could use a simple comma separated list instead after the `or`. The advantage over sealed+private/internal would be thatnthe class or protocol could be public as well.

-Thorsten

Am 25.05.2016 um 04:01 schrieb David Sweeris via swift-evolution <swift-evolution@swift.org>:

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> 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@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> 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> 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
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Thorsten Seitz) #16

Sent from my iPad

Just realized that Matthew did introduce `sealed` exactly to enable this for public types. That's fine with me!

Yeah, and it doesn't require repeating the subclass all in one place which I think is a better fit for Swift.

On the other hand I like that I can see at a glance which subclasses belong to the `sealed` class.

I'm thinking the "exact type" cast (not in my original post) should also be a part of the solution. What do you think of that?

What do you mean by "exact type“ cast?

-Thorsten

···

Am 25.05.2016 um 19:13 schrieb Matthew Johnson <matthew@anandabits.com>:
On May 25, 2016, at 11:18 AM, Thorsten Seitz via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

-Thorsten

Am 25.05.2016 um 18:11 schrieb Thorsten Seitz via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>>:

Ceylon uses the following syntax for stating that a class has a finite set of subclasses:

class C of C1 | C2 {...}

where `|` is the type union operator. Swift could use a simple comma separated list instead after the `or`. The advantage over sealed+private/internal would be thatnthe class or protocol could be public as well.

-Thorsten

Am 25.05.2016 um 04:01 schrieb David Sweeris via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>>:

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 <me@lmpessoa.com <mailto:me@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
>
>
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
> 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

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
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

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution


(Thorsten Seitz) #17

Sent from my iPad

I like the idea of sealed types but I think much better is Ceylon's concept of previously declaring the many subclasses that are going to exist both because I can have a bunch of public classes in a framework and restrict their subclasses and because there are threads in this group discussing the idea of a union type (perhaps both ideas could benefit from one another).

I forgot to mention this in my last reply. What I am proposing allows sealed classes to be viewed as similar to nominal sum types. This is like Scala's case classes.

Ceylon's unions are structural sum types (the sum type analogue of a Tuple, which is a structural product type). I really want to see these as well (I recently ran into a use case where they are far superior to what we can do today). But they are not the same as sealed classes and protocols.

That’s true and readily demonstrated by Ceylon which has both :slight_smile:

-Thorsten

···

Am 25.05.2016 um 19:38 schrieb Matthew Johnson <matthew@anandabits.com>:
On May 25, 2016, at 12:04 PM, Leonardo Pessoa via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Another idea could be to add a single simple keyword to the root class (could even be sealed but I don't think it grabs this concept) to declare all its subclasses must exist within the same module. That would restrict the number of subclasses to the compiler without requiring us to revisit the root class each time we need to create a subclass and would still allow for every subclass to be public.

Sealed wouldn't be a good idea because the root class would still enable subclassing and it would be ideal that the switch could only work with these "sealed" types.

+1 for enabling this for protocols too.

Just a few issues:
- here we're considering having subclasses of subclasses, or not?
-what about public protocols being adopted outside the module, should we just ignore them or completely forbid the adoption?

From: Thorsten Seitz via swift-evolution <mailto:swift-evolution@swift.org>
Sent: ‎25/‎05/‎2016 01:18 PM
To: Thorsten Seitz <mailto:tseitz42@icloud.com>
Cc: swift-evolution <mailto:swift-evolution@swift.org>
Subject: Re: [swift-evolution] [Pitch] Exhaustive pattern matching forprotocols and classes

Just realized that Matthew did introduce `sealed` exactly to enable this for public types. That's fine with me!

-Thorsten

Am 25.05.2016 um 18:11 schrieb Thorsten Seitz via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>>:

Ceylon uses the following syntax for stating that a class has a finite set of subclasses:

class C of C1 | C2 {...}

where `|` is the type union operator. Swift could use a simple comma separated list instead after the `or`. The advantage over sealed+private/internal would be thatnthe class or protocol could be public as well.

-Thorsten

Am 25.05.2016 um 04:01 schrieb David Sweeris via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>>:

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 <me@lmpessoa.com <mailto:me@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
>
>
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
> 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

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
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

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution


(Charlie Monroe) #18

I personally bypass this currently by having an enum of classes defined with an initializer init(instance:) and then switch by the enum, which is safer than switch by type - but it's extra work.

Do you mean safer because you con’t forget to add new cases? Or just safer in general?

Safer as in only having to update one place. When you add one of these classes, you only update the enum (which calls fatalError if it gets an unknown class in the initializer - see example below) - the rest is handled by the compiler. As opposed to searching for all the switches based on type.

Note that this is just a workaround for not having sealed classes for now - I do not mean that this is better than having sealed classes.

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:davesweeris@mac.com>
Sent: ‎24/‎05/‎2016 11:01 PM
To: Austin Zheng <mailto:austinzheng@gmail.com>
Cc: Leonardo Pessoa <mailto:me@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 <me@lmpessoa.com <mailto:me@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
>
>
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
> 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

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
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


(Matthew Johnson) #19

Sent from my iPad

Just realized that Matthew did introduce `sealed` exactly to enable this for public types. That's fine with me!

Yeah, and it doesn't require repeating the subclass all in one place which I think is a better fit for Swift.

On the other hand I like that I can see at a glance which subclasses belong to the `sealed` class.

Yeah, the value of this is the documents on value. The question is whether maintaining it is worth the effort, especially when tools could provide the same information. Reasonable people can disagree on this. I don't feel too strongly about it, but lean slightly towards not requiring the explicit list.

I'm thinking the "exact type" cast (not in my original post) should also be a part of the solution. What do you think of that?

What do you mean by "exact type“ cast?

I mean a cast operator where a subclass will not match a cast to any of its ancestor types. That would let you be sure to provide a case for each individual type and ensure the correct case is selected regardless of order. It can be done today but is verbose and error prone:

case let dog as Dog where dog.dynamicType == Dog.self:

···

Sent from my iPad

On May 26, 2016, at 8:06 AM, Thorsten Seitz <tseitz42@icloud.com> wrote:

Am 25.05.2016 um 19:13 schrieb Matthew Johnson <matthew@anandabits.com>:

On May 25, 2016, at 11:18 AM, Thorsten Seitz via swift-evolution <swift-evolution@swift.org> wrote:

-Thorsten

-Thorsten

Am 25.05.2016 um 18:11 schrieb Thorsten Seitz via swift-evolution <swift-evolution@swift.org>:

Ceylon uses the following syntax for stating that a class has a finite set of subclasses:

class C of C1 | C2 {...}

where `|` is the type union operator. Swift could use a simple comma separated list instead after the `or`. The advantage over sealed+private/internal would be thatnthe class or protocol could be public as well.

-Thorsten

Am 25.05.2016 um 04:01 schrieb David Sweeris via swift-evolution <swift-evolution@swift.org>:

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> 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@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> 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> 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
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Matthew Johnson) #20

I personally bypass this currently by having an enum of classes defined with an initializer init(instance:) and then switch by the enum, which is safer than switch by type - but it's extra work.

Do you mean safer because you con’t forget to add new cases? Or just safer in general?

Safer as in only having to update one place. When you add one of these classes, you only update the enum (which calls fatalError if it gets an unknown class in the initializer - see example below) - the rest is handled by the compiler. As opposed to searching for all the switches based on type.

Note that this is just a workaround for not having sealed classes for now - I do not mean that this is better than having sealed classes.

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.

···

Sent from my iPad

On May 25, 2016, at 12:10 PM, Charlie Monroe <charlie@charliemonroe.net> wrote:

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> 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
Sent: ‎24/‎05/‎2016 11:01 PM
To: Austin Zheng
Cc: Leonardo Pessoa; swift-evolution
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> 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@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> 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> 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
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution