Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-16 Thread David Smith via swift-evolution

> On Feb 15, 2017, at 10:57 PM, Rien  wrote:
> 
> 
> 
>> On 16 Feb 2017, at 03:45, David Smith  wrote:
>> 
>>> 
>>> On Feb 15, 2017, at 8:35 AM, Rien via swift-evolution 
>>>  wrote:
>>> 
 
 On 15 Feb 2017, at 17:02, Matthew Johnson  wrote:
 
> 
> On Feb 15, 2017, at 9:59 AM, Rien  wrote:
> 
>> 
>> On 15 Feb 2017, at 16:45, Matthew Johnson  wrote:
>> 
>>> 
>>> On Feb 15, 2017, at 9:35 AM, Rien  wrote:
>>> 
>>> 
 On 15 Feb 2017, at 16:11, Matthew Johnson via swift-evolution 
  wrote:
 
 
> On Feb 15, 2017, at 5:59 AM, Jeremy Pereira via swift-evolution 
>  wrote:
> 
> 
>> On 15 Feb 2017, at 11:11, Brent Royal-Gordon via swift-evolution 
>>  wrote:
>> 
>> 
>> Our philosophy in general, however, is to default to the behavior 
>> which preserves the most flexibility for the library designer.
> 
> Actually, I thought the philosophy was to preserver type safety. When 
> did that change?
> 
> Also, when was the library designer prioritised ahead of the 
> application developer?
> 
> 
>> Both open and non-open classes are common, but we chose to give 
>> non-open classes the `public` keyword because that's the 
>> flexibility-preserving option.
> 
> No it isn’t, it’s the flexibility restricting option. The consumer of 
> an open class can subclass it. The consumer of a public class cannot 
> subclass it. How is the second more flexible than the first?
 
 It reduces complexity for the library author by allowing them to 
 opt-out of the complexity involved in supporting unknown, user-defined 
 subclasses.  It is important to allow libraries to have this 
 flexibility. They are free to declare a class `open` if they want to 
 allow subclassing. It’s even possibly for a library to declare all 
 classes `open` if it wishes to do so.  But *requiring* that would 
 reduce the design space libraries are allowed to explore and / or 
 introduce fragility by moving the subclass restriction to a comment.
 
>>> 
>>> Why would a library author want to prohibit subclasses?
>>> A library user can always wrap the class and subclass the wrapper.
>> 
>> This is composition, not inheritance.  The most important difference is 
>> that a wrapper cannot override methods, it can only wrap and / or 
>> forward them.  This means that when the superclass calls a method on 
>> `self` that method *always* invokes its version of that method rather 
>> than a subclass override.  This is a very important difference.
>> 
> 
> Agreed, however that does not answer the question why would a library 
> developer want to disallow subclassing?
> I do not see a use case for that. I.e. a feature that cannot be 
> implemented without it. (without “open”)
 
 The feature it enables is more robust libraries and the ability for 
 library authors to better reason about their code.  You may not find this 
 benefit enough to be worth a language feature, but many of us do.
>>> 
>>> You start of with a claim “more robust libraries”.
>>> I would really like to know the “how” of that. How does it make a library 
>>> more robust?
>>> 
>>> I do write libraries myself, and if there is something I am missing, I very 
>>> much would like to know.
>>> 
>>> Regards,
>>> Rien.
>> 
>> The usual thing I've run into in practice follows this general pattern:
>> 
>> • A non-threadsafe class is introduced
>> • Years or decades pass
>> • Someone (me) tries to make the class threadsafe by adding locking
>> • In the intervening years, subclasses have been introduced that override 
>> methods now called while holding a lock, and reentrantly call back into 
>> other methods that take the lock
>> 
>> I've worked around this using recursive mutexes in some cases, but in more 
>> extreme cases the subclass synchronously called out to another thread, and 
>> that thread reentered the lock.
>> 
>> A defensive rule I've adopted in some new code is "public methods are not 
>> allowed to call other public methods", which avoids reentrancy issues, but 
>> also makes subclassing somewhat useless since the work is being done by 
>> private non-overridable methods.
>> 
>>  David
>> 
> 
> That is imo a good usage of this feature “because it exists”.
> However, on my list, it would fall short of making the feature “necessary”.
> 
> Like many access level “problems” they don’t really make something possible, 
> they just 

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-16 Thread Matthew Johnson via swift-evolution

> On Feb 16, 2017, at 8:21 AM, James Froggatt via swift-evolution 
>  wrote:
> 
> 
>> On 16 Feb 2017, at 02:13, Jordan Rose  wrote:
>> 
>> 
>>> On Feb 13, 2017, at 09:28, James Froggatt via swift-evolution 
>>>  wrote:
>>> 
>>> Having loosely followed this discussion, the way I'm thinking of ‘closed’ 
>>> is as a modifier which would let you switch over something from outside the 
>>> module in which it is declared.
>>> 
>>> From outside the declaring module:
>>> • A closed enum's cases can be exhaustively switched.
>>> • A closed protocol's conforming types can be exhaustively switched.
>>> • A closed class's subclasses can be exhaustively switched.
>>> 
>>> If this is correct, I can't help but think ‘closed’ is describing something 
>>> subtly different in each case - picking and choosing the ‘important’ 
>>> relationship for each type, while protocols already have a subtyping 
>>> relationship, and it sounds like there's possibility for enum subtyping in 
>>> the future.
>>> 
>>> I'd rather keep ‘open’ (and a potential future ‘closed’) purely describing 
>>> the subtyping relationship, and have some other means of labelling 
>>> conformance and cases as switchable.
>> 
>> This is definitely not correct. A "closed" enum's cases can be exhaustively 
>> switched from any module, but a non-open protocol's conforming types or 
>> non-open class's subclasses cannot be exhaustively switched from anywhere 
>> except the defining module (because there may be internal subclasses).
>> 
>> Jordan
> 
> Thanks for the correction, I hadn't considered that. Switching over 
> subclasses/conformances could be quite a useful feature in itself, and with 
> the way things are going it would likely need yet another access level…

This could be facilitated by the proposal I put forward that started this 
thread.  The idea is to put enums, classes and protocols on more equal footing. 
 I used the term `closed` in the sense that it is typically used for enums, but 
also allow it to be used with classes and protocols which may be exhaustively 
switched over.  I used `public` in the sense that we say “resilient enum”, 
`public class` or “non-open” protocol.  Finally, I expanded the use of `open` 
to also be applicable to protocols and user-extensible enums.

It will probably be more clear after I share my manifesto on value subtyping 
(coming very soon), but the perspective underlying this idea is that we have 
three different kinds of types which may have concrete subtypes: enums 
(enhanced as I will demonstrate in my value subtyping manifesto), classes and 
protocols.  With this in mind, it seems wise (to me at least) to establish 
common syntax and semantics for controlling how new concrete subtypes may be 
introduced (by users of a module, by future versions of the module, etc).

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


Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-16 Thread James Froggatt via swift-evolution

> On 16 Feb 2017, at 02:13, Jordan Rose  wrote:
> 
> 
>> On Feb 13, 2017, at 09:28, James Froggatt via swift-evolution 
>>  wrote:
>> 
>> Having loosely followed this discussion, the way I'm thinking of ‘closed’ is 
>> as a modifier which would let you switch over something from outside the 
>> module in which it is declared.
>> 
>> From outside the declaring module:
>> • A closed enum's cases can be exhaustively switched.
>> • A closed protocol's conforming types can be exhaustively switched.
>> • A closed class's subclasses can be exhaustively switched.
>> 
>> If this is correct, I can't help but think ‘closed’ is describing something 
>> subtly different in each case - picking and choosing the ‘important’ 
>> relationship for each type, while protocols already have a subtyping 
>> relationship, and it sounds like there's possibility for enum subtyping in 
>> the future.
>> 
>> I'd rather keep ‘open’ (and a potential future ‘closed’) purely describing 
>> the subtyping relationship, and have some other means of labelling 
>> conformance and cases as switchable.
> 
> This is definitely not correct. A "closed" enum's cases can be exhaustively 
> switched from any module, but a non-open protocol's conforming types or 
> non-open class's subclasses cannot be exhaustively switched from anywhere 
> except the defining module (because there may be internal subclasses).
> 
> Jordan

Thanks for the correction, I hadn't considered that. Switching over 
subclasses/conformances could be quite a useful feature in itself, and with the 
way things are going it would likely need yet another access level…
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-15 Thread Rien via swift-evolution


> On 16 Feb 2017, at 03:45, David Smith  wrote:
> 
>> 
>> On Feb 15, 2017, at 8:35 AM, Rien via swift-evolution 
>>  wrote:
>> 
>>> 
>>> On 15 Feb 2017, at 17:02, Matthew Johnson  wrote:
>>> 
 
 On Feb 15, 2017, at 9:59 AM, Rien  wrote:
 
> 
> On 15 Feb 2017, at 16:45, Matthew Johnson  wrote:
> 
>> 
>> On Feb 15, 2017, at 9:35 AM, Rien  wrote:
>> 
>> 
>>> On 15 Feb 2017, at 16:11, Matthew Johnson via swift-evolution 
>>>  wrote:
>>> 
>>> 
 On Feb 15, 2017, at 5:59 AM, Jeremy Pereira via swift-evolution 
  wrote:
 
 
> On 15 Feb 2017, at 11:11, Brent Royal-Gordon via swift-evolution 
>  wrote:
> 
> 
> Our philosophy in general, however, is to default to the behavior 
> which preserves the most flexibility for the library designer.
 
 Actually, I thought the philosophy was to preserver type safety. When 
 did that change?
 
 Also, when was the library designer prioritised ahead of the 
 application developer?
 
 
> Both open and non-open classes are common, but we chose to give 
> non-open classes the `public` keyword because that's the 
> flexibility-preserving option.
 
 No it isn’t, it’s the flexibility restricting option. The consumer of 
 an open class can subclass it. The consumer of a public class cannot 
 subclass it. How is the second more flexible than the first?
>>> 
>>> It reduces complexity for the library author by allowing them to 
>>> opt-out of the complexity involved in supporting unknown, user-defined 
>>> subclasses.  It is important to allow libraries to have this 
>>> flexibility. They are free to declare a class `open` if they want to 
>>> allow subclassing. It’s even possibly for a library to declare all 
>>> classes `open` if it wishes to do so.  But *requiring* that would 
>>> reduce the design space libraries are allowed to explore and / or 
>>> introduce fragility by moving the subclass restriction to a comment.
>>> 
>> 
>> Why would a library author want to prohibit subclasses?
>> A library user can always wrap the class and subclass the wrapper.
> 
> This is composition, not inheritance.  The most important difference is 
> that a wrapper cannot override methods, it can only wrap and / or forward 
> them.  This means that when the superclass calls a method on `self` that 
> method *always* invokes its version of that method rather than a subclass 
> override.  This is a very important difference.
> 
 
 Agreed, however that does not answer the question why would a library 
 developer want to disallow subclassing?
 I do not see a use case for that. I.e. a feature that cannot be 
 implemented without it. (without “open”)
>>> 
>>> The feature it enables is more robust libraries and the ability for library 
>>> authors to better reason about their code.  You may not find this benefit 
>>> enough to be worth a language feature, but many of us do.
>> 
>> You start of with a claim “more robust libraries”.
>> I would really like to know the “how” of that. How does it make a library 
>> more robust?
>> 
>> I do write libraries myself, and if there is something I am missing, I very 
>> much would like to know.
>> 
>> Regards,
>> Rien.
> 
> The usual thing I've run into in practice follows this general pattern:
> 
> • A non-threadsafe class is introduced
> • Years or decades pass
> • Someone (me) tries to make the class threadsafe by adding locking
> • In the intervening years, subclasses have been introduced that override 
> methods now called while holding a lock, and reentrantly call back into other 
> methods that take the lock
> 
> I've worked around this using recursive mutexes in some cases, but in more 
> extreme cases the subclass synchronously called out to another thread, and 
> that thread reentered the lock.
> 
> A defensive rule I've adopted in some new code is "public methods are not 
> allowed to call other public methods", which avoids reentrancy issues, but 
> also makes subclassing somewhat useless since the work is being done by 
> private non-overridable methods.
> 
>   David
> 

That is imo a good usage of this feature “because it exists”.
However, on my list, it would fall short of making the feature “necessary”.

Like many access level “problems” they don’t really make something possible, 
they just document what should not be done. And since nobody RTFM 
(stackoverflow) that may seem like enough to justify something. However it can 
never replaced knowledge.

Regards,
Rien

Site: 

Re: [swift-evolution] [Pitch] consistent public access modifiers (value subtyping digression)

2017-02-15 Thread Matthew Johnson via swift-evolution


Sent from my iPad

> On Feb 15, 2017, at 8:17 PM, Jordan Rose  wrote:
> 
> 
>>> On Feb 13, 2017, at 09:33, Matthew Johnson via swift-evolution 
>>>  wrote:
>>> 
>>> 
>>> On Feb 13, 2017, at 11:28 AM, James Froggatt via swift-evolution 
>>>  wrote:
>>> 
>>> Having loosely followed this discussion, the way I'm thinking of ‘closed’ 
>>> is as a modifier which would let you switch over something from outside the 
>>> module in which it is declared.
>>> 
>>> From outside the declaring module:
>>> • A closed enum's cases can be exhaustively switched.
>>> • A closed protocol's conforming types can be exhaustively switched.
>>> • A closed class's subclasses can be exhaustively switched.
>>> 
>>> If this is correct, I can't help but think ‘closed’ is describing something 
>>> subtly different in each case - picking and choosing the ‘important’ 
>>> relationship for each type, while protocols already have a subtyping 
>>> relationship, and it sounds like there's possibility for enum subtyping in 
>>> the future.
>>> 
>>> I'd rather keep ‘open’ (and a potential future ‘closed’) purely describing 
>>> the subtyping relationship, and have some other means of labelling 
>>> conformance and cases as switchable.
>> 
>> I am drafting a manifesto-style document regarding value subtyping which 
>> will make it clear how value subtypes fit into the picture.  This document 
>> covers the relationship of enum cases with value subtyping and will show 
>> clearly how enum cases are analogous to subclasses.
> 
> I'm not sure how it fits your document, but I suspect value subtyping is 
> pretty much not at all a source-compatibility or binary-compatibility 
> concern. I think the only reasonable implementation here would be to perform 
> conversions (unidirectional or bidirectional?),

I meant to reply to this in my last message.  Yes, the only sensible 
implementation I can think of is via conversion, which may be possible to 
optimize away in some cases where the supertype is representationally 
compatible with the subtype.  Bidirectional conversion / inout wouldn't make 
sense.  If you allow the supertype to mutate you may end up with a value that 
is not representable by the subtype.

> which means that the subtyping is almost entirely a client-side feature and 
> the only potential dynamic operation would be using 'as?' with a generic 
> type. This is very different from protocols and classes, which perform 
> dynamic dispatch to method implementations present on their subtypes.
> 
> That is, the only effect of making a type "non-open" with respect to value 
> subtyping would be to cut down on potential costs of 'as?'.
> 
> Jordan
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Pitch] consistent public access modifiers (value subtyping digression)

2017-02-15 Thread Matthew Johnson via swift-evolution


Sent from my iPad

> On Feb 15, 2017, at 8:17 PM, Jordan Rose  wrote:
> 
> 
>>> On Feb 13, 2017, at 09:33, Matthew Johnson via swift-evolution 
>>>  wrote:
>>> 
>>> 
>>> On Feb 13, 2017, at 11:28 AM, James Froggatt via swift-evolution 
>>>  wrote:
>>> 
>>> Having loosely followed this discussion, the way I'm thinking of ‘closed’ 
>>> is as a modifier which would let you switch over something from outside the 
>>> module in which it is declared.
>>> 
>>> From outside the declaring module:
>>> • A closed enum's cases can be exhaustively switched.
>>> • A closed protocol's conforming types can be exhaustively switched.
>>> • A closed class's subclasses can be exhaustively switched.
>>> 
>>> If this is correct, I can't help but think ‘closed’ is describing something 
>>> subtly different in each case - picking and choosing the ‘important’ 
>>> relationship for each type, while protocols already have a subtyping 
>>> relationship, and it sounds like there's possibility for enum subtyping in 
>>> the future.
>>> 
>>> I'd rather keep ‘open’ (and a potential future ‘closed’) purely describing 
>>> the subtyping relationship, and have some other means of labelling 
>>> conformance and cases as switchable.
>> 
>> I am drafting a manifesto-style document regarding value subtyping which 
>> will make it clear how value subtypes fit into the picture.  This document 
>> covers the relationship of enum cases with value subtyping and will show 
>> clearly how enum cases are analogous to subclasses.
> 
> I'm not sure how it fits your document, but I suspect value subtyping is 
> pretty much not at all a source-compatibility or binary-compatibility 
> concern. I think the only reasonable implementation here would be to perform 
> conversions (unidirectional or bidirectional?), which means that the 
> subtyping is almost entirely a client-side feature and the only potential 
> dynamic operation would be using 'as?' with a generic type. This is very 
> different from protocols and classes, which perform dynamic dispatch to 
> method implementations present on their subtypes.
> 
> That is, the only effect of making a type "non-open" with respect to value 
> subtyping would be to cut down on potential costs of 'as?'.

Thanks for the replies Jordan.  I haven't had a chance to closely look at your 
enum post yet - hopefully tomorrow.

I am not sure how relevant the ideas in my document are to language ABI but I 
suspect you are right that they are not very relevant there.  I am less certain 
about the standard library (and haven't done any work to try and asses that 
either).  

My thought is to share a manifesto-style document and ask the community to try 
to identify anything that might be relevant and keep the immediate conversation 
focused on that.  The rest will have to wait until the time is right.

> 
> Jordan
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-15 Thread David Smith via swift-evolution

> On Feb 15, 2017, at 8:35 AM, Rien via swift-evolution 
>  wrote:
> 
>> 
>> On 15 Feb 2017, at 17:02, Matthew Johnson  wrote:
>> 
>>> 
>>> On Feb 15, 2017, at 9:59 AM, Rien  wrote:
>>> 
 
 On 15 Feb 2017, at 16:45, Matthew Johnson  wrote:
 
> 
> On Feb 15, 2017, at 9:35 AM, Rien  wrote:
> 
> 
>> On 15 Feb 2017, at 16:11, Matthew Johnson via swift-evolution 
>>  wrote:
>> 
>> 
>>> On Feb 15, 2017, at 5:59 AM, Jeremy Pereira via swift-evolution 
>>>  wrote:
>>> 
>>> 
 On 15 Feb 2017, at 11:11, Brent Royal-Gordon via swift-evolution 
  wrote:
 
 
 Our philosophy in general, however, is to default to the behavior 
 which preserves the most flexibility for the library designer.
>>> 
>>> Actually, I thought the philosophy was to preserver type safety. When 
>>> did that change?
>>> 
>>> Also, when was the library designer prioritised ahead of the 
>>> application developer?
>>> 
>>> 
 Both open and non-open classes are common, but we chose to give 
 non-open classes the `public` keyword because that's the 
 flexibility-preserving option.
>>> 
>>> No it isn’t, it’s the flexibility restricting option. The consumer of 
>>> an open class can subclass it. The consumer of a public class cannot 
>>> subclass it. How is the second more flexible than the first?
>> 
>> It reduces complexity for the library author by allowing them to opt-out 
>> of the complexity involved in supporting unknown, user-defined 
>> subclasses.  It is important to allow libraries to have this 
>> flexibility. They are free to declare a class `open` if they want to 
>> allow subclassing. It’s even possibly for a library to declare all 
>> classes `open` if it wishes to do so.  But *requiring* that would reduce 
>> the design space libraries are allowed to explore and / or introduce 
>> fragility by moving the subclass restriction to a comment.
>> 
> 
> Why would a library author want to prohibit subclasses?
> A library user can always wrap the class and subclass the wrapper.
 
 This is composition, not inheritance.  The most important difference is 
 that a wrapper cannot override methods, it can only wrap and / or forward 
 them.  This means that when the superclass calls a method on `self` that 
 method *always* invokes its version of that method rather than a subclass 
 override.  This is a very important difference.
 
>>> 
>>> Agreed, however that does not answer the question why would a library 
>>> developer want to disallow subclassing?
>>> I do not see a use case for that. I.e. a feature that cannot be implemented 
>>> without it. (without “open”)
>> 
>> The feature it enables is more robust libraries and the ability for library 
>> authors to better reason about their code.  You may not find this benefit 
>> enough to be worth a language feature, but many of us do.
> 
> You start of with a claim “more robust libraries”.
> I would really like to know the “how” of that. How does it make a library 
> more robust?
> 
> I do write libraries myself, and if there is something I am missing, I very 
> much would like to know.
> 
> Regards,
> Rien.

The usual thing I've run into in practice follows this general pattern:

• A non-threadsafe class is introduced
• Years or decades pass
• Someone (me) tries to make the class threadsafe by adding locking
• In the intervening years, subclasses have been introduced that override 
methods now called while holding a lock, and reentrantly call back into other 
methods that take the lock

I've worked around this using recursive mutexes in some cases, but in more 
extreme cases the subclass synchronously called out to another thread, and that 
thread reentered the lock.

A defensive rule I've adopted in some new code is "public methods are not 
allowed to call other public methods", which avoids reentrancy issues, but also 
makes subclassing somewhat useless since the work is being done by private 
non-overridable methods.

David


> 
>> 
>>> 
>>> Rien.
>>> 
> 
> There are cases where subclassing does not make sense. And thus 
> preventing subclasses adds information for those users that don’t RTFM. 
> But that imo is not worth the impact extra complexity places on all other 
> users.
> 
> Rien.
> 
>>> 
>>> 
>>> ___
>>> swift-evolution mailing list
>>> swift-evolution@swift.org
>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>> 
>> ___
>> swift-evolution mailing list
>> 

Re: [swift-evolution] [Pitch] consistent public access modifiers - protocols

2017-02-15 Thread Jordan Rose via swift-evolution

> On Feb 10, 2017, at 12:23, Matthew Johnson  wrote:
> 
> 
>> On Feb 10, 2017, at 12:52 PM, Jordan Rose > > wrote:
>> 
>> Hi, Matthew. Thank you for bringing up these issues. I'm going to break my 
>> feedback up into separate messages, because I think really the enum and 
>> protocol cases are unrelated. Open classes refer to classes that can be 
>> subclassed from clients of the current module, and similarly open protocols 
>> would be protocols that can be adopted from clients of the current module. 
>> Public-but-not-open classes cannot be subclassed from outside the current 
>> module, but they can still be subclassed within the module. By contrast, 
>> "open" enums can grow new cases in new versions of the library, but clients 
>> still can't add cases. (That's not a totally unreasonable feature to ever 
>> consider, but it's not the one we need now.)
> 
> Hi Jordan.  Thanks for replying to my post!
> 
> I understand the current behavior of `open` and how it would work for 
> protocols.  I also understand the vocabulary that has been used in talking 
> about “open” enums thus far.  What I am trying to point out is that there are 
> inconsistencies in the vocabulary we’ve been using thus far.  
> 
> The ideas of “open” and “closed” both talk about who is able to add to the 
> set of cases / subclasses / conforming types.  `public` (without annotation) 
> also does this.  But we haven’t been using the terms consistently - we use a 
> different meaning depending on which kind of entity we’re talking about.
> 
> For example, as you pointed out, `open` currently means both a module *and* 
> its clients can add new subclasses.  It doesn’t seem right to use this same 
> terminology to mean the module can add cases to an enum but clients *can’t* 
> add new cases to the enum.  I understand that “open” enums in the sense of 
> the current meaning of the `open` keyword are not a feature we need right 
> away.  I noted that this is specifically not proposed in my pitch.  But if we 
> ever *do* add this feature, `open enum` seems like the right way to spell it 
> (probably just using the existing case syntax in an extension to add cases in 
> the client).
> 
> It’s also worth pointing out that `public` currently has three distinct 
> meanings:
> * `public` enums *cannot* have a new case added in a future version of the 
> library is without a breaking change
> * `public` classes *can* have a new subclass added in a future version of the 
> library without a breaking change, but clients cannot add subclasses
> * `public` protocols have the same semantics as `open` classes, allowing 
> clients to add conforming types

* public structs *can* have new fields added
* public functions *can* add new parameters, as long as they have defaults, if 
you are careful about it
* public types *can* have new subtypes added
* public types *can* have new conformances added, although today that will 
break people and we need to do something about that (on another thread)

I think this is just a false equivalence. Adding cases to an enum within a 
module is fundamentally different from adding subclasses to a class outside the 
module. We should not be trying to jam enums into the same keyword that classes 
use just because I happened to use that term when writing the Library Evolution 
doc, even if it is a reasonable term for the thing.

(Matthew was very quick about replying to my first message and I was very slow 
with the second, and I think I already made this point better there. But for 
cross-referencing purposes it made sense to mention it here too.)


>> P.S. For classes, note that 'final' is essentially a performance 
>> optimization at this point. I'm not even sure we should bother displaying it 
>> in generated interfaces (although the compiler should still be able to take 
>> advantage of it in clients).
> 
> `final` can be pretty useful when reasoning about code.  It’s more than just 
> a performance optimization.  It also represents a compiler proof about our 
> code.

Ah, sorry, yes: 'final' is totally useful within a module to have the property 
enforced. It's just not super interesting outside the module. (It doesn't even 
mean there are no subclasses in all cases; features like KVO use a dynamic 
subclass in their implementation.)

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


Re: [swift-evolution] [Pitch] consistent public access modifiers (value subtyping digression)

2017-02-15 Thread Jordan Rose via swift-evolution

> On Feb 13, 2017, at 09:33, Matthew Johnson via swift-evolution 
>  wrote:
> 
>> 
>> On Feb 13, 2017, at 11:28 AM, James Froggatt via swift-evolution 
>>  wrote:
>> 
>> Having loosely followed this discussion, the way I'm thinking of ‘closed’ is 
>> as a modifier which would let you switch over something from outside the 
>> module in which it is declared.
>> 
>> From outside the declaring module:
>> • A closed enum's cases can be exhaustively switched.
>> • A closed protocol's conforming types can be exhaustively switched.
>> • A closed class's subclasses can be exhaustively switched.
>> 
>> If this is correct, I can't help but think ‘closed’ is describing something 
>> subtly different in each case - picking and choosing the ‘important’ 
>> relationship for each type, while protocols already have a subtyping 
>> relationship, and it sounds like there's possibility for enum subtyping in 
>> the future.
>> 
>> I'd rather keep ‘open’ (and a potential future ‘closed’) purely describing 
>> the subtyping relationship, and have some other means of labelling 
>> conformance and cases as switchable.
> 
> I am drafting a manifesto-style document regarding value subtyping which will 
> make it clear how value subtypes fit into the picture.  This document covers 
> the relationship of enum cases with value subtyping and will show clearly how 
> enum cases are analogous to subclasses.

I'm not sure how it fits your document, but I suspect value subtyping is pretty 
much not at all a source-compatibility or binary-compatibility concern. I think 
the only reasonable implementation here would be to perform conversions 
(unidirectional or bidirectional?), which means that the subtyping is almost 
entirely a client-side feature and the only potential dynamic operation would 
be using 'as?' with a generic type. This is very different from protocols and 
classes, which perform dynamic dispatch to method implementations present on 
their subtypes.

That is, the only effect of making a type "non-open" with respect to value 
subtyping would be to cut down on potential costs of 'as?'.

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


Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-15 Thread Jordan Rose via swift-evolution

> On Feb 13, 2017, at 09:28, James Froggatt via swift-evolution 
>  wrote:
> 
> Having loosely followed this discussion, the way I'm thinking of ‘closed’ is 
> as a modifier which would let you switch over something from outside the 
> module in which it is declared.
> 
> From outside the declaring module:
> • A closed enum's cases can be exhaustively switched.
> • A closed protocol's conforming types can be exhaustively switched.
> • A closed class's subclasses can be exhaustively switched.
> 
> If this is correct, I can't help but think ‘closed’ is describing something 
> subtly different in each case - picking and choosing the ‘important’ 
> relationship for each type, while protocols already have a subtyping 
> relationship, and it sounds like there's possibility for enum subtyping in 
> the future.
> 
> I'd rather keep ‘open’ (and a potential future ‘closed’) purely describing 
> the subtyping relationship, and have some other means of labelling 
> conformance and cases as switchable.

This is definitely not correct. A "closed" enum's cases can be exhaustively 
switched from any module, but a non-open protocol's conforming types or 
non-open class's subclasses cannot be exhaustively switched from anywhere 
except the defining module (because there may be internal subclasses).

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


Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-15 Thread Jordan Rose via swift-evolution


> On Feb 14, 2017, at 18:16, Xiaodi Wu via swift-evolution 
>  wrote:
> 
> So, perhaps I'm being simplistic here, but--
> 
> At the end of the day, aren't we simply trying to enable a resiliency 
> feature? Could it not be said that an enum where future added cases aren't 
> source-breaking is a more resilient enum?
> 
> Since there is consensus that the status quo is desirable for a lot of use 
> cases, couldn't we keep spelling it "public enum" and just spell this 
> proposed more resilient enum "@resilient public enum"?

Not quite. Resilience is about making changes that aren't source-breaking also 
not ABI-breaking (within reason, balanced against performance implications). 
"Open" vs. "non-open" enums also affect modules distributed as source—is it a 
source-breaking change to add a new case or not?

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


Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-15 Thread Jordan Rose via swift-evolution

> On Feb 12, 2017, at 21:52, Slava Pestov via swift-evolution 
>  wrote:
> 
> Also, note that there will be at least one other similar annotation, but for 
> structs — the evolution document calls it @fixedContents. We want a way to 
> declare that the set of stored properties in a struct will never change, 
> allowing clients to make assumptions about its layout. Unlike @closed enums, 
> @fixedContents structs mostly behave the same. The one important difference 
> is that it will be possible to define designated initializers of 
> @fixedContents structs inside extensions from another module.

The "@fixedContents mostly doesn't change the behavior of a struct" makes me 
think it is unimportant for these two annotations to have the same name.

Jordan

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


Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-15 Thread Jordan Rose via swift-evolution
> The Library Evolution document isn’t gospel; it’s more like a collection of 
> musings and aspirations, so I don’t think we should be bound by the syntax it 
> uses.

Agreed on this very local point. :-) There are some deliberately ugly names in 
there so that we don't end up using that syntax.

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


Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-15 Thread David Waite via swift-evolution
Types have a ton of different implicit/explicit “API”, and access control 
modifiers often implicitly define that API:

- API for everyone to use when dealing with your concrete type (“public”)
- API for module code when you have related, coupled types that need a higher 
degree of knowledge (“internal”)
- API for within the implementation of the type itself (“fileprivate”/“private”)
- API to other code to interact with your type in a more general manner 
(protocol implementation)
- You also have two versions of each of these - instance and static/class-level 
properties/methods (including initializers)
- Each of these can also have stability aspects - which versions of a framework 
support the API, whether the API is deprecated or obsoleted, etc. (exposed 
partially today via “#available")

And classes add even more!:
- Whether subclassing is allowed (‘final’)
- API for subclasses to use for their implementation, but not meant for general 
usage (typically “protected")
- API which subclasses are allowed to override to implement new logic (“open")
- API which subclasses are forbidden to override because they define business 
logic used by coupled code ("final"/"closed")
- API which subclasses are required to override (typically “abstract" base 
classes - Swift and Objective C seem to prefer Delegates instead)

(I’m probably forgetting a few)

So access levels serve three main purposes:
1. to define these API so that a developer interacting with your type knows 
what is or is not (for instance) a subclass knows what it is or is not allowed 
to change, code using your types know what is or is not safe to call, etc.
2. to try to enforce these API to be used  only by the intend audience
3. to prevent reliance on implementation details as a stable API

Obviously not all of these cases need compiler-enforcement of the API - nor 
could you have a simple enough system for general purpose consumption which 
attempted to do so. In the case language features do not document the 
stakeholders or behavior of the API, regular documentation and processes should 
attempt to do so. 

This IMHO was the majority of the argument against SE-0025 - that if you are 
already in the same file, you must know the implementation details well enough 
to know what is or is not safe API. If developers were putting too much code 
within a single file was a case for a level above fileprivate, not below it. 
This why I personally pushed to defer until there was a submodule design.

The public/internal/private model is nice because it mirrors code locality, and 
thus is focused on enforcement of safety. If some other code depends on 
implementation details of my type that I don’t want to expose to the world, 
that code is going to be in the same module or even the same file. Hiding 
implementation details is enforcement for safety.

Classes obviously provide an explosion of complexity in defining behavior 
because of the additional relationship with sub- and super-classes. I generally 
push people away from designing their packages to rely on subclassing (instead 
preferring protocols and aggregation) because keeping this complexity straight 
and having a good design that reduces coupling is so difficult when dealing 
with subclassing.

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


Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-15 Thread Adrian Zubarev via swift-evolution
Not a huge response, but how about locked?



-- 
Adrian Zubarev
Sent with Airmail

Am 15. Februar 2017 um 20:31:30, Matthew Johnson via swift-evolution 
(swift-evolution@swift.org) schrieb:


> On Feb 14, 2017, at 3:43 AM, Brent Royal-Gordon  
> wrote:
>  
>> On Feb 13, 2017, at 7:45 AM, Matthew Johnson  wrote:
>>  
>> If you look closely, when most people say “closed enum” they mean a fixed, 
>> complete set of cases that are all public. But when people say “closed 
>> protocol” they don’t actually mean a fixed, complete set of conformances 
>> that are all public. They simply mean clients cannot add conformances. This 
>> is the semantic contract of resilient enums, not closed enums.
>  
> Yes, our traditional terminology here has been a little bit confused.
>  
>>> What I instead suggest is that we think of a closed enum as being like a 
>>> fragile (non-resilient) struct. In both cases, you are committing to a 
>>> particular design for the type. So I think we should give them both the 
>>> same keyword—something like:
>>>  
>>> @fixed struct Person {
>>> var name: String
>>> var birthDate: Date
>>> }
>>> @fixed enum Edge {
>>> case start
>>> case end
>>> }
>>>  
>>  
>> You omitted public here. Does that mean you intend for `@fixed` to imply 
>> public visibility? If so, I could get behind this. But I am curious why you 
>> made it an attribute rather than a keyword.
>  
> No, I'm sorry, I meant to say `@fixed public struct` and `@fixed public 
> enum`. I don't think `@fixed` implies public-ness, either, so it would need 
> to be paired with a `public` keyword. There *may* be keywords we could use 
> that would, like `exposed`, but I'm not sure we want to make this feature so 
> prominent, and I'm not sure how that would work with classes you want to both 
> expose and permit subclassing of. (Would that be `exposed open class Foo`?)

I thought of a couple of other possible keywords. I had previously mentioned 
`complete` as an alternative to `closed`. Another option that goes in this 
direction is `total` - it borrows from the mathematical notion of a total 
function. I’m not sure how I feel about this option and it still doesn’t 
necessarily imply “more public than public” very strongly (only in the sense 
that its totality is known to all which is a rather weak sense).

Another possibility is `transparent`. This does imply “more public than public” 
a some sense that is similar to `open`. I know `@transparent` (or something 
like that) has been used as an unsupported(?) attribute hinting to the compiler 
that a function should be made available for inlining (what is the current 
status of this?). The meaning of this attribute is in some ways similar to the 
meaning you ascribe to `fixed`. In all cases, this is only meaningful for 
`public` entities so it feels like a promising direction.  

The one thing that makes me somewhat uncomfortable with this approach is that 
in the context of structs and functions it has no semantic impact on user code 
- it is only an optimization, while for enums it wold make a important semantic 
difference to user code. I’m not sure we should use the same syntax for 
something that is sometimes an optimization and sometimes is semantically 
meaningful. This concern is relevant regardless of what the keyword is called.

>  
>>> I don't see it mentioned here (maybe I just missed it), but even though we 
>>> *could* do exhaustiveness checking on non-open protocols, I'm not convinced 
>>> that's a good idea. Usually when you have several types conforming to a 
>>> protocol, you should access type-specific behavior through polymorphism, 
>>> not by switching on the protocol. A protocol is supposed to represent a 
>>> behavior, not just mark a type in some arbitrary way.
>>  
>> I agree that you should usually be adding polymorphism, but preventing 
>> exhaustive switch on what is effectively a style argument seems like an 
>> unnecessary restriction to me. There will be times when it could be used to 
>> good effect. I think the community has done a pretty good job of figuring 
>> out how to use Swift’s many features well and don’t believe it would be 
>> frequently abused.
>  
> I agree we shouldn't change the language to *prevent* bad style. But this 
> would go beyond that—we'd be putting specific engineering effort solely into 
> *enabling* bad style. At minimum, this should fall so far down our to-do list 
> that we'll probably never get to it.
>  
>>> I still support this general approach. One spelling could simply be 
>>> `@nonopen`. Although if we don't use `closed`, we could simply use 
>>> `@closed` like I suggested—here it really *would* be an antonym to `open`.
>>  
>> I like the idea of using `@nonopen` for the transitional attribute. Both 
>> because it “removes the openness” that `public protocol` currently implies. 
>> In that sense it is probably the most accurate term we could find and it’s 
>> also pretty 

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-15 Thread Matthew Johnson via swift-evolution

> On Feb 14, 2017, at 3:43 AM, Brent Royal-Gordon  
> wrote:
> 
>> On Feb 13, 2017, at 7:45 AM, Matthew Johnson  wrote:
>> 
>> If you look closely, when most people say “closed enum” they mean a fixed, 
>> complete set of cases that are all public.  But when people say “closed 
>> protocol” they don’t actually mean a fixed, complete set of conformances 
>> that are all public.  They simply mean clients cannot add conformances.  
>> This is the semantic contract of resilient enums, not closed enums.
> 
> Yes, our traditional terminology here has been a little bit confused.
> 
>>> What I instead suggest is that we think of a closed enum as being like a 
>>> fragile (non-resilient) struct. In both cases, you are committing to a 
>>> particular design for the type. So I think we should give them both the 
>>> same keyword—something like:
>>> 
>>> @fixed struct Person {
>>> var name: String
>>> var birthDate: Date
>>> }
>>> @fixed enum Edge {
>>> case start
>>> case end
>>> }
>>> 
>> 
>> You omitted public here.  Does that mean you intend for `@fixed` to imply 
>> public visibility?  If so, I could get behind this.  But I am curious why 
>> you made it an attribute rather than a keyword.
> 
> No, I'm sorry, I meant to say `@fixed public struct` and `@fixed public 
> enum`. I don't think `@fixed` implies public-ness, either, so it would need 
> to be paired with a `public` keyword. There *may* be keywords we could use 
> that would, like `exposed`, but I'm not sure we want to make this feature so 
> prominent, and I'm not sure how that would work with classes you want to both 
> expose and permit subclassing of. (Would that be `exposed open class Foo`?)

I thought of a couple of other possible keywords.  I had previously mentioned 
`complete` as an alternative to `closed`.  Another option that goes in this 
direction is `total` - it borrows from the mathematical notion of a total 
function.  I’m not sure how I feel about this option and it still doesn’t 
necessarily imply “more public than public” very strongly (only in the sense 
that its totality is known to all which is a rather weak sense).

Another possibility is `transparent`.  This does imply “more public than 
public” a some sense that is similar to `open`.  I know `@transparent` (or 
something like that) has been used as an unsupported(?) attribute hinting to 
the compiler that a function should be made available for inlining (what is the 
current status of this?).  The meaning of this attribute is in some ways 
similar to the meaning you ascribe to `fixed`.  In all cases, this is only 
meaningful for `public` entities so it feels like a promising direction.  

The one thing that makes me somewhat uncomfortable with this approach is that 
in the context of structs and functions it has no semantic impact on user code 
- it is only an optimization, while for enums it wold make a important semantic 
difference to user code.  I’m not sure we should use the same syntax for 
something that is sometimes an optimization and sometimes is semantically 
meaningful.  This concern is relevant regardless of what the keyword is called.

> 
>>> I don't see it mentioned here (maybe I just missed it), but even though we 
>>> *could* do exhaustiveness checking on non-open protocols, I'm not convinced 
>>> that's a good idea. Usually when you have several types conforming to a 
>>> protocol, you should access type-specific behavior through polymorphism, 
>>> not by switching on the protocol. A protocol is supposed to represent a 
>>> behavior, not just mark a type in some arbitrary way.
>> 
>> I agree that you should usually be adding polymorphism, but preventing 
>> exhaustive switch on what is effectively a style argument seems like an 
>> unnecessary restriction to me.  There will be times when it could be used to 
>> good effect.  I think the community has done a pretty good job of figuring 
>> out how to use Swift’s many features well and don’t believe it would be 
>> frequently abused.
> 
> I agree we shouldn't change the language to *prevent* bad style. But this 
> would go beyond that—we'd be putting specific engineering effort solely into 
> *enabling* bad style. At minimum, this should fall so far down our to-do list 
> that we'll probably never get to it.
> 
>>> I still support this general approach. One spelling could simply be 
>>> `@nonopen`. Although if we don't use `closed`, we could simply use 
>>> `@closed` like I suggested—here it really *would* be an antonym to `open`.
>> 
>> I like the idea of using `@nonopen` for the transitional attribute.  Both 
>> because it “removes the openness” that `public protocol` currently implies.  
>> In that sense it is probably the most accurate term we could find and it’s 
>> also pretty concise.
> 
> It also sounds a little bit awkward, which is normally a reason not to use 
> it, but perhaps that's 

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-15 Thread Rien via swift-evolution
> 
> On 15 Feb 2017, at 19:27, Adrian Zubarev  
> wrote:
> 
> Inline:
> 
> -- 
> Adrian Zubarev
> Sent with Airmail
> 
> Am 15. Februar 2017 um 19:11:12, Rien (r...@balancingrock.nl) schrieb:
> 
>> 
>> > On 15 Feb 2017, at 18:09, Adrian Zubarev  
>> > wrote: 
>> > 
>> > As I already said: 
>> > 
>> > • To make that feature happen, we need the protocol to be public 
>> > (regardless if you can conform to it or not). 
>> > • Today you can conform to every protocol because in reality they are open 
>> > today. 
>> > • If we remove the property requirement from the protocol the client can 
>> > conform it to any type and break my API by calling the subscript with a 
>> > wrong type: document["something", NSObject()] (assuming extension NSObject 
>> > : SubscriptParameterType). 
>> > • That forces me to create a requirement for the protocol which solves the 
>> > issue in my cases, however there might exist other issues, which could be 
>> > far more complicated than mine is. 
>> > • That also implies I have make the enum public. 
>> > • Which follows by the fact that I’m creating unnecessary copy operations 
>> > to wrap every instance that conforms to my protocol into an enum case. 
>> > From internal API perspective I also have to unwrap the enum case. 
>> > Instead if we had consistent public vs. open behavior, I could make the 
>> > protocol public (but-not-open), remove the requirement from it completely, 
>> > remove the enum completely and simply cast to Int or String because as the 
>> > author of the library I would know that the client won’t be able to 
>> > conform to my protocol. 
>> > 
>> > Importing my library will show the client only this: 
>> > 
>> > extension Int : SubscriptParameterType {} 
>> > extension String : SubscriptParameterType {} 
>> > 
>> > 
>> 
>> Ok, thanks, I think I get it now. So you showed the work-around rather than 
>> the problem :-) 
>> However you could also implement this by creating two subscript operations, 
>> one for integer and one for string. 
> No not really, the idea behind this approach is carefully crafted. Plus I do 
> not want optional chaining between subscripts, this is messy 
> `document[“string”]?[10]?[“key”]`.

Yes, but there are always more ways to skin a cat :-)
In my SwifterJSON I do use both an int and a string subscript and have solved 
the optional chaining (rather ugly… but it works).
Also, I overloaded the pipe (“|”) operator that allows me to do away with the 
array notation like this: … = json | ”books” | 3 | “title"


> 
>> 
>> 
>> So while I agree that this might serve as an example on why a 
>> non-confirmable protocol might be useful, my original question still stands: 
>> how can subclassing create “brittle” libraries? 
> If one would want the client user only to use subclasses of a certain 
> superclass of the same library for whatever reasons. These subclasses might 
> interact with each other internally (which is not meant to be public by any 
> means). `final public` will not make it happen because then you couldn’t 
> create any of these subclasses at all.
> 
> You’re asking here such a general question that simply cannot be answered 
> easily. I also could ask everyone why on earth would be want to hide anything 
> from the client? Lets make everything public, if the client breaks something 
> it’s his fault. <— Clearly not the way to go right? A distinction between 
> `public` and `open` adds more flexibility to solve issues that previously 
> might not had any good solutions.

It does, I am not doubting that at all.
But there are always costs, adding an extra keyword and an extra access layer 
adds complexity, adds possibilities for errors, leads to more testing, 
increases cognitive load, steepens the learning curve etc etc. And it does so 
for ALL swift users. Possibly far outweighing the benefits that accrue to 
(maybe) just a few developers.

(Like the infamous tax problem: people won’t spend much effort to change the 
tax system and pay $1 a year less in taxes, but the one organisation/person 
receiving all those dollars has a huge incentive and will spend -if necessary- 
all his time to keep the system as is)

> 
>> 
>> 
>> Also note that adding an extra access level did nothing to prevent brittle 
>> libraries… that task is still with the developer. 
>> 
>> PS, this is not an educational list, so … :-) 
> Being sarcastic? 

No, not really. I just wanted to draw attention to the fact that there is no 
obligation whatsoever to teach me.
So thank you for taking the time!

In your debt,
Rien.

> 
>> 
>> 
>> Regards, 
>> Rien. 
>> 
>> > 
>> > 
>> > -- 
>> > Adrian Zubarev 
>> > Sent with Airmail 
>> > 
>> > Am 15. Februar 2017 um 17:50:41, Rien (r...@balancingrock.nl) schrieb: 
>> > 
>> >> 
>> >> > On 15 Feb 2017, at 17:22, Adrian Zubarev via swift-evolution 
>> >> >  wrote: 
>> >> >  
>> >> > A short example where I personally wanted 

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-15 Thread Adrian Zubarev via swift-evolution
If you happen not to bump into these issues yet, then simply call yourself 
lucky. ;)

-- 
Adrian Zubarev
Sent with Airmail

Am 15. Februar 2017 um 19:27:06, Adrian Zubarev 
(adrian.zuba...@devandartist.com) schrieb:

Inline:

-- 
Adrian Zubarev
Sent with Airmail

Am 15. Februar 2017 um 19:11:12, Rien (r...@balancingrock.nl) schrieb:


> On 15 Feb 2017, at 18:09, Adrian Zubarev  
> wrote: 
> 
> As I already said: 
> 
> • To make that feature happen, we need the protocol to be public (regardless 
> if you can conform to it or not). 
> • Today you can conform to every protocol because in reality they are open 
> today. 
> • If we remove the property requirement from the protocol the client can 
> conform it to any type and break my API by calling the subscript with a wrong 
> type: document["something", NSObject()] (assuming extension NSObject : 
> SubscriptParameterType). 
> • That forces me to create a requirement for the protocol which solves the 
> issue in my cases, however there might exist other issues, which could be far 
> more complicated than mine is. 
> • That also implies I have make the enum public. 
> • Which follows by the fact that I’m creating unnecessary copy operations to 
> wrap every instance that conforms to my protocol into an enum case. From 
> internal API perspective I also have to unwrap the enum case. 
> Instead if we had consistent public vs. open behavior, I could make the 
> protocol public (but-not-open), remove the requirement from it completely, 
> remove the enum completely and simply cast to Int or String because as the 
> author of the library I would know that the client won’t be able to conform 
> to my protocol. 
> 
> Importing my library will show the client only this: 
> 
> extension Int : SubscriptParameterType {} 
> extension String : SubscriptParameterType {} 
> 
> 

Ok, thanks, I think I get it now. So you showed the work-around rather than the 
problem :-) 
However you could also implement this by creating two subscript operations, one 
for integer and one for string. 
No not really, the idea behind this approach is carefully crafted. Plus I do 
not want optional chaining between subscripts, this is messy 
`document[“string”]?[10]?[“key”]`.



So while I agree that this might serve as an example on why a non-confirmable 
protocol might be useful, my original question still stands: how can 
subclassing create “brittle” libraries? 
If one would want the client user only to use subclasses of a certain 
superclass of the same library for whatever reasons. These subclasses might 
interact with each other internally (which is not meant to be public by any 
means). `final public` will not make it happen because then you couldn’t create 
any of these subclasses at all.

You’re asking here such a general question that simply cannot be answered 
easily. I also could ask everyone why on earth would be want to hide anything 
from the client? Lets make everything public, if the client breaks something 
it’s his fault. <— Clearly not the way to go right? A distinction between 
`public` and `open` adds more flexibility to solve issues that previously might 
not had any good solutions.



Also note that adding an extra access level did nothing to prevent brittle 
libraries… that task is still with the developer. 

PS, this is not an educational list, so … :-) 
Being sarcastic? 



Regards, 
Rien. 

> 
> 
> -- 
> Adrian Zubarev 
> Sent with Airmail 
> 
> Am 15. Februar 2017 um 17:50:41, Rien (r...@balancingrock.nl) schrieb: 
> 
>> 
>> > On 15 Feb 2017, at 17:22, Adrian Zubarev via swift-evolution 
>> >  wrote: 
>> >  
>> > A short example where I personally wanted a public-but-not-open protocol: 
>> >  
>> > public protocol SubscriptParameterType { 
>> >  
>> > // This property was needed to prevent the client from breaking 
>> > // the library by conforming to the protocol, but I'd like to  
>> > // keep it invisible for the client, or even better prevent the 
>> > // client from conforming to the protocol. 
>> > var parameter: Document.SubscriptParameter { get } 
>> > } 
>> >  
>> > extension Document { 
>> >  
>> > public enum SubscriptParameter { 
>> >  
>> > case string(String) 
>> > case integer(Int) 
>> > } 
>> > } 
>> >  
>> > extension String : SubscriptParameterType { 
>> >  
>> > public var parameter: Document.SubscriptParameter { 
>> >  
>> > return .string(self) 
>> > } 
>> > } 
>> >  
>> > extension Int : SubscriptParameterType { 
>> >  
>> > public var parameter: Document.SubscriptParameter { 
>> >  
>> > return .integer(self) 
>> > } 
>> > } 
>> >  
>> > // Somewhere inside the `Document` type 
>> > public subscript(firstKey: String, parameters: SubscriptParameterType...) 
>> > -> Value? { … } 
>> >  
>> > That implementation enables more safe queries of my Document type like 
>> > document["key1", intIndexInstance, stringKeyInstance, 10, "key"] rather 
>> > than 

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-15 Thread Adrian Zubarev via swift-evolution
Inline:

-- 
Adrian Zubarev
Sent with Airmail

Am 15. Februar 2017 um 19:11:12, Rien (r...@balancingrock.nl) schrieb:


> On 15 Feb 2017, at 18:09, Adrian Zubarev  
> wrote: 
> 
> As I already said: 
> 
> • To make that feature happen, we need the protocol to be public (regardless 
> if you can conform to it or not). 
> • Today you can conform to every protocol because in reality they are open 
> today. 
> • If we remove the property requirement from the protocol the client can 
> conform it to any type and break my API by calling the subscript with a wrong 
> type: document["something", NSObject()] (assuming extension NSObject : 
> SubscriptParameterType). 
> • That forces me to create a requirement for the protocol which solves the 
> issue in my cases, however there might exist other issues, which could be far 
> more complicated than mine is. 
> • That also implies I have make the enum public. 
> • Which follows by the fact that I’m creating unnecessary copy operations to 
> wrap every instance that conforms to my protocol into an enum case. From 
> internal API perspective I also have to unwrap the enum case. 
> Instead if we had consistent public vs. open behavior, I could make the 
> protocol public (but-not-open), remove the requirement from it completely, 
> remove the enum completely and simply cast to Int or String because as the 
> author of the library I would know that the client won’t be able to conform 
> to my protocol. 
> 
> Importing my library will show the client only this: 
> 
> extension Int : SubscriptParameterType {} 
> extension String : SubscriptParameterType {} 
> 
> 

Ok, thanks, I think I get it now. So you showed the work-around rather than the 
problem :-) 
However you could also implement this by creating two subscript operations, one 
for integer and one for string. 
No not really, the idea behind this approach is carefully crafted. Plus I do 
not want optional chaining between subscripts, this is messy 
`document[“string”]?[10]?[“key”]`.



So while I agree that this might serve as an example on why a non-confirmable 
protocol might be useful, my original question still stands: how can 
subclassing create “brittle” libraries? 
If one would want the client user only to use subclasses of a certain 
superclass of the same library for whatever reasons. These subclasses might 
interact with each other internally (which is not meant to be public by any 
means). `final public` will not make it happen because then you couldn’t create 
any of these subclasses at all.

You’re asking here such a general question that simply cannot be answered 
easily. I also could ask everyone why on earth would be want to hide anything 
from the client? Lets make everything public, if the client breaks something 
it’s his fault. <— Clearly not the way to go right? A distinction between 
`public` and `open` adds more flexibility to solve issues that previously might 
not had any good solutions.



Also note that adding an extra access level did nothing to prevent brittle 
libraries… that task is still with the developer. 

PS, this is not an educational list, so … :-) 
Being sarcastic? 



Regards, 
Rien. 

> 
> 
> -- 
> Adrian Zubarev 
> Sent with Airmail 
> 
> Am 15. Februar 2017 um 17:50:41, Rien (r...@balancingrock.nl) schrieb: 
> 
>> 
>> > On 15 Feb 2017, at 17:22, Adrian Zubarev via swift-evolution 
>> >  wrote: 
>> >  
>> > A short example where I personally wanted a public-but-not-open protocol: 
>> >  
>> > public protocol SubscriptParameterType { 
>> >  
>> > // This property was needed to prevent the client from breaking 
>> > // the library by conforming to the protocol, but I'd like to  
>> > // keep it invisible for the client, or even better prevent the 
>> > // client from conforming to the protocol. 
>> > var parameter: Document.SubscriptParameter { get } 
>> > } 
>> >  
>> > extension Document { 
>> >  
>> > public enum SubscriptParameter { 
>> >  
>> > case string(String) 
>> > case integer(Int) 
>> > } 
>> > } 
>> >  
>> > extension String : SubscriptParameterType { 
>> >  
>> > public var parameter: Document.SubscriptParameter { 
>> >  
>> > return .string(self) 
>> > } 
>> > } 
>> >  
>> > extension Int : SubscriptParameterType { 
>> >  
>> > public var parameter: Document.SubscriptParameter { 
>> >  
>> > return .integer(self) 
>> > } 
>> > } 
>> >  
>> > // Somewhere inside the `Document` type 
>> > public subscript(firstKey: String, parameters: SubscriptParameterType...) 
>> > -> Value? { … } 
>> >  
>> > That implementation enables more safe queries of my Document type like 
>> > document["key1", intIndexInstance, stringKeyInstance, 10, "key"] rather 
>> > than document["key1/\(intIndexInstance)/\(stringKeyInstance)/10/key”] 
>> 
>> I see how that makes queries better. 
>> However what I do not see is how making the protocol “open” would make this 
>> less safe. 
>> (I do not see a reason to make it open either, 

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-15 Thread Adrian Zubarev via swift-evolution
I’ll try again to make it a little bit more simpler.

Assume we want to implement my feature to support document["string_literal", 
stringInstance, integerInstance, 42] where the first parameter type is always a 
String but the types follow afterward are either a String or an Int (literals 
should be supported too).

// Module A
// Today only `public` is allowed on protocols.
// `public protocol` means almost the same as `open class`.
// One is 'you can conform to it outside module A'
// the other is 'you can subclass to it outside module A'

// First idea
public SubscriptParameterType {}
extension Int : SubscriptParameterType {}
extension String : SubscriptParameterType {}

extension Document {
 
public subscript(firstKey: String, parameters: SubscriptParameterType...) 
-> Value? {  
 
// CAST any instance of `SubscriptParameterType` to Int or String
}
}

// Module B
extension NSObject : SubscriptParameterType {}

// Lets try breaking module A
document["test", NSObject()] // Runtime error, because something unexpected 
happened in module A

// The reason is we let the client (module B) the ability to conform to our 
type without any requirements.

// To solve that issue we need TODAY a requirement on our protocol 
`SubscriptParameterType` (see my previous post)
// I already mentioned that the workaround creates unnecessary boilerplate in 
my library.

// We could clean everything up iff we had consistent `public` vs. `open` 
behavior. I will use `pulic-but-not-open` and `open` annotation now.

pulic-but-not-open SubscriptParameterType {}
extension Int : SubscriptParameterType {}
extension String : SubscriptParameterType {}

// Module B
extension NSObject : SubscriptParameterType {} // Error, 
`SubscriptParameterType` is closed and cannot be conformed to outside module A!!
This feature is ridiculously powerful.



-- 
Adrian Zubarev
Sent with Airmail

Am 15. Februar 2017 um 18:57:50, Rien via swift-evolution 
(swift-evolution@swift.org) schrieb:


> On 15 Feb 2017, at 17:45, Matthew Johnson  wrote:
>  
>  
>> On Feb 15, 2017, at 10:35 AM, Rien  wrote:
>>  
>>>  
>>> On 15 Feb 2017, at 17:02, Matthew Johnson  wrote:
>>>  
  
 On Feb 15, 2017, at 9:59 AM, Rien  wrote:
  
>  
> On 15 Feb 2017, at 16:45, Matthew Johnson  wrote:
>  
>>  
>> On Feb 15, 2017, at 9:35 AM, Rien  wrote:
>>  
>>  
>>> On 15 Feb 2017, at 16:11, Matthew Johnson via swift-evolution 
>>>  wrote:
>>>  
>>>  
 On Feb 15, 2017, at 5:59 AM, Jeremy Pereira via swift-evolution 
  wrote:
  
  
> On 15 Feb 2017, at 11:11, Brent Royal-Gordon via swift-evolution 
>  wrote:
>  
>  
> Our philosophy in general, however, is to default to the behavior 
> which preserves the most flexibility for the library designer.
  
 Actually, I thought the philosophy was to preserver type safety. When 
 did that change?
  
 Also, when was the library designer prioritised ahead of the 
 application developer?
  
  
> Both open and non-open classes are common, but we chose to give 
> non-open classes the `public` keyword because that's the 
> flexibility-preserving option.
  
 No it isn’t, it’s the flexibility restricting option. The consumer of 
 an open class can subclass it. The consumer of a public class cannot 
 subclass it. How is the second more flexible than the first?
>>>  
>>> It reduces complexity for the library author by allowing them to 
>>> opt-out of the complexity involved in supporting unknown, user-defined 
>>> subclasses. It is important to allow libraries to have this 
>>> flexibility. They are free to declare a class `open` if they want to 
>>> allow subclassing. It’s even possibly for a library to declare all 
>>> classes `open` if it wishes to do so. But *requiring* that would reduce 
>>> the design space libraries are allowed to explore and / or introduce 
>>> fragility by moving the subclass restriction to a comment.
>>>  
>>  
>> Why would a library author want to prohibit subclasses?
>> A library user can always wrap the class and subclass the wrapper.
>  
> This is composition, not inheritance. The most important difference is 
> that a wrapper cannot override methods, it can only wrap and / or forward 
> them. This means that when the superclass calls a method on `self` that 
> method *always* invokes its version of that method rather than a subclass 
> override. This is a very important difference.
>  
  
 Agreed, however that does not answer the 

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-15 Thread Rien via swift-evolution

> On 15 Feb 2017, at 18:09, Adrian Zubarev  
> wrote:
> 
> As I already said:
> 
>   • To make that feature happen, we need the protocol to be public 
> (regardless if you can conform to it or not).
>   • Today you can conform to every protocol because in reality they are 
> open today.
>   • If we remove the property requirement from the protocol the client 
> can conform it to any type and break my API by calling the subscript with a 
> wrong type: document["something", NSObject()] (assuming extension NSObject : 
> SubscriptParameterType).
>   • That forces me to create a requirement for the protocol which solves 
> the issue in my cases, however there might exist other issues, which could be 
> far more complicated than mine is.
>   • That also implies I have make the enum public.
>   • Which follows by the fact that I’m creating unnecessary copy 
> operations to wrap every instance that conforms to my protocol into an enum 
> case. From internal API perspective I also have to unwrap the enum case.
> Instead if we had consistent public vs. open behavior, I could make the 
> protocol public (but-not-open), remove the requirement from it completely, 
> remove the enum completely and simply cast to Int or String because as the 
> author of the library I would know that the client won’t be able to conform 
> to my protocol.
> 
> Importing my library will show the client only this:
> 
> extension Int : SubscriptParameterType {}
> extension String : SubscriptParameterType {}
> 
> 

Ok, thanks, I think I get it now. So you showed the work-around rather than the 
problem :-)
However you could also implement this by creating two subscript operations, one 
for integer and one for string.

So while I agree that this might serve as an example on why a non-confirmable 
protocol might be useful, my original question still stands: how can 
subclassing create “brittle” libraries?

Also note that adding an extra access level did nothing to prevent brittle 
libraries… that task is still with the developer.

PS, this is not an educational list, so … :-)

Regards,
Rien.

> 
> 
> -- 
> Adrian Zubarev
> Sent with Airmail
> 
> Am 15. Februar 2017 um 17:50:41, Rien (r...@balancingrock.nl) schrieb:
> 
>> 
>> > On 15 Feb 2017, at 17:22, Adrian Zubarev via swift-evolution 
>> >  wrote: 
>> >  
>> > A short example where I personally wanted a public-but-not-open protocol: 
>> >  
>> > public protocol SubscriptParameterType { 
>> >  
>> > // This property was needed to prevent the client from breaking 
>> > // the library by conforming to the protocol, but I'd like to  
>> > // keep it invisible for the client, or even better prevent the 
>> > // client from conforming to the protocol. 
>> > var parameter: Document.SubscriptParameter { get } 
>> > } 
>> >  
>> > extension Document { 
>> >  
>> > public enum SubscriptParameter { 
>> >  
>> > case string(String) 
>> > case integer(Int) 
>> > } 
>> > } 
>> >  
>> > extension String : SubscriptParameterType { 
>> >  
>> > public var parameter: Document.SubscriptParameter { 
>> >  
>> > return .string(self) 
>> > } 
>> > } 
>> >  
>> > extension Int : SubscriptParameterType { 
>> >  
>> > public var parameter: Document.SubscriptParameter { 
>> >  
>> > return .integer(self) 
>> > } 
>> > } 
>> >  
>> > // Somewhere inside the `Document` type 
>> > public subscript(firstKey: String, parameters: SubscriptParameterType...) 
>> > -> Value? { … } 
>> >  
>> > That implementation enables more safe queries of my Document type like 
>> > document["key1", intIndexInstance, stringKeyInstance, 10, "key"] rather 
>> > than document["key1/\(intIndexInstance)/\(stringKeyInstance)/10/key”] 
>> 
>> I see how that makes queries better. 
>> However what I do not see is how making the protocol “open” would make this 
>> less safe. 
>> (I do not see a reason to make it open either, but that is not the question) 
>> 
>> It may be obvious to everyone else, but I don’t see it. Am I suffering from 
>> a brain freeze?. 
>> 
>> Regards, 
>> Rien. 
>> 
>> 
>> > . 
>> >  
>> 
>> >  
>> >  
>> >  
>> > --  
>> > Adrian Zubarev 
>> > Sent with Airmail 
>> >  
>> > Am 15. Februar 2017 um 17:03:32, Matthew Johnson via swift-evolution 
>> > (swift-evolution@swift.org) schrieb: 
>> >  
>> >>  
>> >>> On Feb 15, 2017, at 9:59 AM, Rien  wrote: 
>> >>>  
>>   
>>  On 15 Feb 2017, at 16:45, Matthew Johnson  
>>  wrote: 
>>   
>> >  
>> > On Feb 15, 2017, at 9:35 AM, Rien  wrote: 
>> >  
>> >  
>> >> On 15 Feb 2017, at 16:11, Matthew Johnson via swift-evolution 
>> >>  wrote: 
>> >>  
>> >>  
>> >>> On Feb 15, 2017, at 5:59 AM, Jeremy Pereira via swift-evolution 
>> >>>  wrote: 
>> >>>  
>> >>>  
>>  On 15 Feb 2017, at 11:11, Brent Royal-Gordon via 

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-15 Thread Rien via swift-evolution

> On 15 Feb 2017, at 17:45, Matthew Johnson  wrote:
> 
> 
>> On Feb 15, 2017, at 10:35 AM, Rien  wrote:
>> 
>>> 
>>> On 15 Feb 2017, at 17:02, Matthew Johnson  wrote:
>>> 
 
 On Feb 15, 2017, at 9:59 AM, Rien  wrote:
 
> 
> On 15 Feb 2017, at 16:45, Matthew Johnson  wrote:
> 
>> 
>> On Feb 15, 2017, at 9:35 AM, Rien  wrote:
>> 
>> 
>>> On 15 Feb 2017, at 16:11, Matthew Johnson via swift-evolution 
>>>  wrote:
>>> 
>>> 
 On Feb 15, 2017, at 5:59 AM, Jeremy Pereira via swift-evolution 
  wrote:
 
 
> On 15 Feb 2017, at 11:11, Brent Royal-Gordon via swift-evolution 
>  wrote:
> 
> 
> Our philosophy in general, however, is to default to the behavior 
> which preserves the most flexibility for the library designer.
 
 Actually, I thought the philosophy was to preserver type safety. When 
 did that change?
 
 Also, when was the library designer prioritised ahead of the 
 application developer?
 
 
> Both open and non-open classes are common, but we chose to give 
> non-open classes the `public` keyword because that's the 
> flexibility-preserving option.
 
 No it isn’t, it’s the flexibility restricting option. The consumer of 
 an open class can subclass it. The consumer of a public class cannot 
 subclass it. How is the second more flexible than the first?
>>> 
>>> It reduces complexity for the library author by allowing them to 
>>> opt-out of the complexity involved in supporting unknown, user-defined 
>>> subclasses.  It is important to allow libraries to have this 
>>> flexibility. They are free to declare a class `open` if they want to 
>>> allow subclassing. It’s even possibly for a library to declare all 
>>> classes `open` if it wishes to do so.  But *requiring* that would 
>>> reduce the design space libraries are allowed to explore and / or 
>>> introduce fragility by moving the subclass restriction to a comment.
>>> 
>> 
>> Why would a library author want to prohibit subclasses?
>> A library user can always wrap the class and subclass the wrapper.
> 
> This is composition, not inheritance.  The most important difference is 
> that a wrapper cannot override methods, it can only wrap and / or forward 
> them.  This means that when the superclass calls a method on `self` that 
> method *always* invokes its version of that method rather than a subclass 
> override.  This is a very important difference.
> 
 
 Agreed, however that does not answer the question why would a library 
 developer want to disallow subclassing?
 I do not see a use case for that. I.e. a feature that cannot be 
 implemented without it. (without “open”)
>>> 
>>> The feature it enables is more robust libraries and the ability for library 
>>> authors to better reason about their code.  You may not find this benefit 
>>> enough to be worth a language feature, but many of us do.
>> 
>> You start of with a claim “more robust libraries”.
>> I would really like to know the “how” of that. How does it make a library 
>> more robust?
>> 
>> I do write libraries myself, and if there is something I am missing, I very 
>> much would like to know.
> 
> This topic was well explored during the discussion and review of the proposal 
> that introduced `open`.  If you would really like to know I suggest you take 
> some time to read through that discussion.

I did (proposal 117), while it was mentioned a few times “if not carefully 
designed for subclassing” there is no example on how open vs public prevents 
anything.

Mind you, it could be argued that the default of “internal” instead of “open” 
can prevent something (though I still don’t know what). But adding “open” does 
imo not prevent anything.

Besides: a monkey with a tool is still a monkey.

I.e. devs that now start using “open” vs “public” because it all is a hassle to 
figure out what should be “internal”, “public” or “open” will still make the 
same errors (which ones?) as before.
Thus while there is a lot of bad code around (partly mine!) that does not 
disappear because the default is not “not subclassable”.

(PS: I am still trying to get my head around Adrian’s example)

Regards,
Rien.

> 
>> 
>> Regards,
>> Rien.
>> 
>>> 
 
 Rien.
 
>> 
>> There are cases where subclassing does not make sense. And thus 
>> preventing subclasses adds information for those users that don’t RTFM. 
>> But that imo is not worth the impact extra complexity places on all 
>> other users.
>> 
>> Rien.

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-15 Thread Adrian Zubarev via swift-evolution
To summarize everything, I think whenever we get submodules in Swift having a 
consistent public vs. open behavior would have a great impact when some of us 
will work on huge (team) projects.

I do not actively support the idea of @closed. I see its benefits, but first I 
need to get my head around it’s complete behavior (on all different types, on 
their members). That said I’ll be more quite on that problem. :)



-- 
Adrian Zubarev
Sent with Airmail

Am 15. Februar 2017 um 18:09:52, Adrian Zubarev 
(adrian.zuba...@devandartist.com) schrieb:

As I already said:

To make that feature happen, we need the protocol to be public (regardless if 
you can conform to it or not).
Today you can conform to every protocol because in reality they are open today.
If we remove the property requirement from the protocol the client can conform 
it to any type and break my API by calling the subscript with a wrong type: 
document["something", NSObject()] (assuming extension NSObject : 
SubscriptParameterType).
That forces me to create a requirement for the protocol which solves the issue 
in my cases, however there might exist other issues, which could be far more 
complicated than mine is.
That also implies I have make the enum public.
Which follows by the fact that I’m creating unnecessary copy operations to wrap 
every instance that conforms to my protocol into an enum case. From internal 
API perspective I also have to unwrap the enum case.
Instead if we had consistent public vs. open behavior, I could make the 
protocol public (but-not-open), remove the requirement from it completely, 
remove the enum completely and simply cast to Int or String because as the 
author of the library I would know that the client won’t be able to conform to 
my protocol.

Importing my library will show the client only this:

extension Int : SubscriptParameterType {}
extension String : SubscriptParameterType {}


-- 
Adrian Zubarev
Sent with Airmail

Am 15. Februar 2017 um 17:50:41, Rien (r...@balancingrock.nl) schrieb:


> On 15 Feb 2017, at 17:22, Adrian Zubarev via swift-evolution 
>  wrote:
>
> A short example where I personally wanted a public-but-not-open protocol:
>
> public protocol SubscriptParameterType {
>
> // This property was needed to prevent the client from breaking
> // the library by conforming to the protocol, but I'd like to
> // keep it invisible for the client, or even better prevent the
> // client from conforming to the protocol.
> var parameter: Document.SubscriptParameter { get }
> }
>
> extension Document {
>
> public enum SubscriptParameter {
>
> case string(String)
> case integer(Int)
> }
> }
>
> extension String : SubscriptParameterType {
>
> public var parameter: Document.SubscriptParameter {
>
> return .string(self)
> }
> }
>
> extension Int : SubscriptParameterType {
>
> public var parameter: Document.SubscriptParameter {
>
> return .integer(self)
> }
> }
>
> // Somewhere inside the `Document` type
> public subscript(firstKey: String, parameters: SubscriptParameterType...) -> 
> Value? { … }
>
> That implementation enables more safe queries of my Document type like 
> document["key1", intIndexInstance, stringKeyInstance, 10, "key"] rather than 
> document["key1/\(intIndexInstance)/\(stringKeyInstance)/10/key”]

I see how that makes queries better.
However what I do not see is how making the protocol “open” would make this 
less safe.
(I do not see a reason to make it open either, but that is not the question)

It may be obvious to everyone else, but I don’t see it. Am I suffering from a 
brain freeze?.

Regards,
Rien.


> .
>

>
>
>
> --
> Adrian Zubarev
> Sent with Airmail
>
> Am 15. Februar 2017 um 17:03:32, Matthew Johnson via swift-evolution 
> (swift-evolution@swift.org) schrieb:
>
>>
>>> On Feb 15, 2017, at 9:59 AM, Rien  wrote:
>>>

 On 15 Feb 2017, at 16:45, Matthew Johnson  wrote:

>
> On Feb 15, 2017, at 9:35 AM, Rien  wrote:
>
>
>> On 15 Feb 2017, at 16:11, Matthew Johnson via swift-evolution 
>>  wrote:
>>
>>
>>> On Feb 15, 2017, at 5:59 AM, Jeremy Pereira via swift-evolution 
>>>  wrote:
>>>
>>>
 On 15 Feb 2017, at 11:11, Brent Royal-Gordon via swift-evolution 
  wrote:


 Our philosophy in general, however, is to default to the behavior 
 which preserves the most flexibility for the library designer.
>>>
>>> Actually, I thought the philosophy was to preserver type safety. When 
>>> did that change?
>>>
>>> Also, when was the library designer prioritised ahead of the 
>>> application developer?
>>>
>>>
 Both open and non-open classes are common, but we chose to give 
 non-open classes the `public` keyword because that's the 
 flexibility-preserving option.

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-15 Thread Adrian Zubarev via swift-evolution
As I already said:

To make that feature happen, we need the protocol to be public (regardless if 
you can conform to it or not).
Today you can conform to every protocol because in reality they are open today.
If we remove the property requirement from the protocol the client can conform 
it to any type and break my API by calling the subscript with a wrong type: 
document["something", NSObject()] (assuming extension NSObject : 
SubscriptParameterType).
That forces me to create a requirement for the protocol which solves the issue 
in my cases, however there might exist other issues, which could be far more 
complicated than mine is.
That also implies I have make the enum public.
Which follows by the fact that I’m creating unnecessary copy operations to wrap 
every instance that conforms to my protocol into an enum case. From internal 
API perspective I also have to unwrap the enum case.
Instead if we had consistent public vs. open behavior, I could make the 
protocol public (but-not-open), remove the requirement from it completely, 
remove the enum completely and simply cast to Int or String because as the 
author of the library I would know that the client won’t be able to conform to 
my protocol.

Importing my library will show the client only this:

extension Int : SubscriptParameterType {}
extension String : SubscriptParameterType {}


-- 
Adrian Zubarev
Sent with Airmail

Am 15. Februar 2017 um 17:50:41, Rien (r...@balancingrock.nl) schrieb:


> On 15 Feb 2017, at 17:22, Adrian Zubarev via swift-evolution 
>  wrote:  
>  
> A short example where I personally wanted a public-but-not-open protocol:  
>  
> public protocol SubscriptParameterType {  
>  
> // This property was needed to prevent the client from breaking  
> // the library by conforming to the protocol, but I'd like to  
> // keep it invisible for the client, or even better prevent the  
> // client from conforming to the protocol.  
> var parameter: Document.SubscriptParameter { get }  
> }  
>  
> extension Document {  
>  
> public enum SubscriptParameter {  
>  
> case string(String)  
> case integer(Int)  
> }  
> }  
>  
> extension String : SubscriptParameterType {  
>  
> public var parameter: Document.SubscriptParameter {  
>  
> return .string(self)  
> }  
> }  
>  
> extension Int : SubscriptParameterType {  
>  
> public var parameter: Document.SubscriptParameter {  
>  
> return .integer(self)  
> }  
> }  
>  
> // Somewhere inside the `Document` type  
> public subscript(firstKey: String, parameters: SubscriptParameterType...) -> 
> Value? { … }  
>  
> That implementation enables more safe queries of my Document type like 
> document["key1", intIndexInstance, stringKeyInstance, 10, "key"] rather than 
> document["key1/\(intIndexInstance)/\(stringKeyInstance)/10/key”]  

I see how that makes queries better.  
However what I do not see is how making the protocol “open” would make this 
less safe.  
(I do not see a reason to make it open either, but that is not the question)  

It may be obvious to everyone else, but I don’t see it. Am I suffering from a 
brain freeze?.  

Regards,  
Rien.  


> .  
>  

>  
>  
>  
> --  
> Adrian Zubarev  
> Sent with Airmail  
>  
> Am 15. Februar 2017 um 17:03:32, Matthew Johnson via swift-evolution 
> (swift-evolution@swift.org) schrieb:  
>  
>>  
>>> On Feb 15, 2017, at 9:59 AM, Rien  wrote:  
>>>  
  
 On 15 Feb 2017, at 16:45, Matthew Johnson  wrote:  
  
>  
> On Feb 15, 2017, at 9:35 AM, Rien  wrote:  
>  
>  
>> On 15 Feb 2017, at 16:11, Matthew Johnson via swift-evolution 
>>  wrote:  
>>  
>>  
>>> On Feb 15, 2017, at 5:59 AM, Jeremy Pereira via swift-evolution 
>>>  wrote:  
>>>  
>>>  
 On 15 Feb 2017, at 11:11, Brent Royal-Gordon via swift-evolution 
  wrote:  
  
  
 Our philosophy in general, however, is to default to the behavior 
 which preserves the most flexibility for the library designer.  
>>>  
>>> Actually, I thought the philosophy was to preserver type safety. When 
>>> did that change?  
>>>  
>>> Also, when was the library designer prioritised ahead of the 
>>> application developer?  
>>>  
>>>  
 Both open and non-open classes are common, but we chose to give 
 non-open classes the `public` keyword because that's the 
 flexibility-preserving option.  
>>>  
>>> No it isn’t, it’s the flexibility restricting option. The consumer of 
>>> an open class can subclass it. The consumer of a public class cannot 
>>> subclass it. How is the second more flexible than the first?  
>>  
>> It reduces complexity for the library author by allowing them to opt-out 
>> of the complexity involved in supporting 

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-15 Thread Rien via swift-evolution

> On 15 Feb 2017, at 17:22, Adrian Zubarev via swift-evolution 
>  wrote:
> 
> A short example where I personally wanted a public-but-not-open protocol:
> 
> public protocol SubscriptParameterType {
>  
> // This property was needed to prevent the client from breaking
> // the library by conforming to the protocol, but I'd like to  
> // keep it invisible for the client, or even better prevent the
> // client from conforming to the protocol.
> var parameter: Document.SubscriptParameter { get }
> }
> 
> extension Document {
>  
> public enum SubscriptParameter {
>  
> case string(String)
> case integer(Int)
> }
> }
> 
> extension String : SubscriptParameterType {
>  
> public var parameter: Document.SubscriptParameter {
>  
> return .string(self)
> }
> }
> 
> extension Int : SubscriptParameterType {
>  
> public var parameter: Document.SubscriptParameter {
>  
> return .integer(self)
> }
> }
> 
> // Somewhere inside the `Document` type
> public subscript(firstKey: String, parameters: SubscriptParameterType...) -> 
> Value? { … }
> 
> That implementation enables more safe queries of my Document type like 
> document["key1", intIndexInstance, stringKeyInstance, 10, "key"] rather than 
> document["key1/\(intIndexInstance)/\(stringKeyInstance)/10/key”]

I see how that makes queries better.
However what I do not see is how making the protocol “open” would make this 
less safe.
(I do not see a reason to make it open either, but that is not the question)

It may be obvious to everyone else, but I don’t see it. Am I suffering from a 
brain freeze?.

Regards,
Rien.


> .
> 

> 
> 
> 
> -- 
> Adrian Zubarev
> Sent with Airmail
> 
> Am 15. Februar 2017 um 17:03:32, Matthew Johnson via swift-evolution 
> (swift-evolution@swift.org) schrieb:
> 
>> 
>>> On Feb 15, 2017, at 9:59 AM, Rien  wrote:
>>> 
 
 On 15 Feb 2017, at 16:45, Matthew Johnson  wrote:
 
> 
> On Feb 15, 2017, at 9:35 AM, Rien  wrote:
> 
> 
>> On 15 Feb 2017, at 16:11, Matthew Johnson via swift-evolution 
>>  wrote:
>> 
>> 
>>> On Feb 15, 2017, at 5:59 AM, Jeremy Pereira via swift-evolution 
>>>  wrote:
>>> 
>>> 
 On 15 Feb 2017, at 11:11, Brent Royal-Gordon via swift-evolution 
  wrote:
 
 
 Our philosophy in general, however, is to default to the behavior 
 which preserves the most flexibility for the library designer.
>>> 
>>> Actually, I thought the philosophy was to preserver type safety. When 
>>> did that change?
>>> 
>>> Also, when was the library designer prioritised ahead of the 
>>> application developer?
>>> 
>>> 
 Both open and non-open classes are common, but we chose to give 
 non-open classes the `public` keyword because that's the 
 flexibility-preserving option.
>>> 
>>> No it isn’t, it’s the flexibility restricting option. The consumer of 
>>> an open class can subclass it. The consumer of a public class cannot 
>>> subclass it. How is the second more flexible than the first?
>> 
>> It reduces complexity for the library author by allowing them to opt-out 
>> of the complexity involved in supporting unknown, user-defined 
>> subclasses.  It is important to allow libraries to have this 
>> flexibility. They are free to declare a class `open` if they want to 
>> allow subclassing. It’s even possibly for a library to declare all 
>> classes `open` if it wishes to do so.  But *requiring* that would reduce 
>> the design space libraries are allowed to explore and / or introduce 
>> fragility by moving the subclass restriction to a comment.
>> 
> 
> Why would a library author want to prohibit subclasses?
> A library user can always wrap the class and subclass the wrapper.
 
 This is composition, not inheritance.  The most important difference is 
 that a wrapper cannot override methods, it can only wrap and / or forward 
 them.  This means that when the superclass calls a method on `self` that 
 method *always* invokes its version of that method rather than a subclass 
 override.  This is a very important difference.
 
>>> 
>>> Agreed, however that does not answer the question why would a library 
>>> developer want to disallow subclassing?
>>> I do not see a use case for that. I.e. a feature that cannot be implemented 
>>> without it. (without “open”)
>> 
>> The feature it enables is more robust libraries and the ability for library 
>> authors to better reason about their code.  You may not find this benefit 
>> enough to be worth a language feature, but many of us do.
>> 
>>> 
>>> Rien.
>>> 

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-15 Thread Matthew Johnson via swift-evolution

> On Feb 15, 2017, at 10:35 AM, Rien  wrote:
> 
>> 
>> On 15 Feb 2017, at 17:02, Matthew Johnson  wrote:
>> 
>>> 
>>> On Feb 15, 2017, at 9:59 AM, Rien  wrote:
>>> 
 
 On 15 Feb 2017, at 16:45, Matthew Johnson  wrote:
 
> 
> On Feb 15, 2017, at 9:35 AM, Rien  wrote:
> 
> 
>> On 15 Feb 2017, at 16:11, Matthew Johnson via swift-evolution 
>>  wrote:
>> 
>> 
>>> On Feb 15, 2017, at 5:59 AM, Jeremy Pereira via swift-evolution 
>>>  wrote:
>>> 
>>> 
 On 15 Feb 2017, at 11:11, Brent Royal-Gordon via swift-evolution 
  wrote:
 
 
 Our philosophy in general, however, is to default to the behavior 
 which preserves the most flexibility for the library designer.
>>> 
>>> Actually, I thought the philosophy was to preserver type safety. When 
>>> did that change?
>>> 
>>> Also, when was the library designer prioritised ahead of the 
>>> application developer?
>>> 
>>> 
 Both open and non-open classes are common, but we chose to give 
 non-open classes the `public` keyword because that's the 
 flexibility-preserving option.
>>> 
>>> No it isn’t, it’s the flexibility restricting option. The consumer of 
>>> an open class can subclass it. The consumer of a public class cannot 
>>> subclass it. How is the second more flexible than the first?
>> 
>> It reduces complexity for the library author by allowing them to opt-out 
>> of the complexity involved in supporting unknown, user-defined 
>> subclasses.  It is important to allow libraries to have this 
>> flexibility. They are free to declare a class `open` if they want to 
>> allow subclassing. It’s even possibly for a library to declare all 
>> classes `open` if it wishes to do so.  But *requiring* that would reduce 
>> the design space libraries are allowed to explore and / or introduce 
>> fragility by moving the subclass restriction to a comment.
>> 
> 
> Why would a library author want to prohibit subclasses?
> A library user can always wrap the class and subclass the wrapper.
 
 This is composition, not inheritance.  The most important difference is 
 that a wrapper cannot override methods, it can only wrap and / or forward 
 them.  This means that when the superclass calls a method on `self` that 
 method *always* invokes its version of that method rather than a subclass 
 override.  This is a very important difference.
 
>>> 
>>> Agreed, however that does not answer the question why would a library 
>>> developer want to disallow subclassing?
>>> I do not see a use case for that. I.e. a feature that cannot be implemented 
>>> without it. (without “open”)
>> 
>> The feature it enables is more robust libraries and the ability for library 
>> authors to better reason about their code.  You may not find this benefit 
>> enough to be worth a language feature, but many of us do.
> 
> You start of with a claim “more robust libraries”.
> I would really like to know the “how” of that. How does it make a library 
> more robust?
> 
> I do write libraries myself, and if there is something I am missing, I very 
> much would like to know.

This topic was well explored during the discussion and review of the proposal 
that introduced `open`.  If you would really like to know I suggest you take 
some time to read through that discussion.

> 
> Regards,
> Rien.
> 
>> 
>>> 
>>> Rien.
>>> 
> 
> There are cases where subclassing does not make sense. And thus 
> preventing subclasses adds information for those users that don’t RTFM. 
> But that imo is not worth the impact extra complexity places on all other 
> users.
> 
> Rien.
> 
>>> 
>>> 
>>> ___
>>> 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


Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-15 Thread Rien via swift-evolution

> On 15 Feb 2017, at 17:02, Matthew Johnson  wrote:
> 
>> 
>> On Feb 15, 2017, at 9:59 AM, Rien  wrote:
>> 
>>> 
>>> On 15 Feb 2017, at 16:45, Matthew Johnson  wrote:
>>> 
 
 On Feb 15, 2017, at 9:35 AM, Rien  wrote:
 
 
> On 15 Feb 2017, at 16:11, Matthew Johnson via swift-evolution 
>  wrote:
> 
> 
>> On Feb 15, 2017, at 5:59 AM, Jeremy Pereira via swift-evolution 
>>  wrote:
>> 
>> 
>>> On 15 Feb 2017, at 11:11, Brent Royal-Gordon via swift-evolution 
>>>  wrote:
>>> 
>>> 
>>> Our philosophy in general, however, is to default to the behavior which 
>>> preserves the most flexibility for the library designer.
>> 
>> Actually, I thought the philosophy was to preserver type safety. When 
>> did that change?
>> 
>> Also, when was the library designer prioritised ahead of the application 
>> developer?
>> 
>> 
>>> Both open and non-open classes are common, but we chose to give 
>>> non-open classes the `public` keyword because that's the 
>>> flexibility-preserving option.
>> 
>> No it isn’t, it’s the flexibility restricting option. The consumer of an 
>> open class can subclass it. The consumer of a public class cannot 
>> subclass it. How is the second more flexible than the first?
> 
> It reduces complexity for the library author by allowing them to opt-out 
> of the complexity involved in supporting unknown, user-defined 
> subclasses.  It is important to allow libraries to have this flexibility. 
> They are free to declare a class `open` if they want to allow 
> subclassing. It’s even possibly for a library to declare all classes 
> `open` if it wishes to do so.  But *requiring* that would reduce the 
> design space libraries are allowed to explore and / or introduce 
> fragility by moving the subclass restriction to a comment.
> 
 
 Why would a library author want to prohibit subclasses?
 A library user can always wrap the class and subclass the wrapper.
>>> 
>>> This is composition, not inheritance.  The most important difference is 
>>> that a wrapper cannot override methods, it can only wrap and / or forward 
>>> them.  This means that when the superclass calls a method on `self` that 
>>> method *always* invokes its version of that method rather than a subclass 
>>> override.  This is a very important difference.
>>> 
>> 
>> Agreed, however that does not answer the question why would a library 
>> developer want to disallow subclassing?
>> I do not see a use case for that. I.e. a feature that cannot be implemented 
>> without it. (without “open”)
> 
> The feature it enables is more robust libraries and the ability for library 
> authors to better reason about their code.  You may not find this benefit 
> enough to be worth a language feature, but many of us do.

You start of with a claim “more robust libraries”.
I would really like to know the “how” of that. How does it make a library more 
robust?

I do write libraries myself, and if there is something I am missing, I very 
much would like to know.

Regards,
Rien.

> 
>> 
>> Rien.
>> 
 
 There are cases where subclassing does not make sense. And thus preventing 
 subclasses adds information for those users that don’t RTFM. But that imo 
 is not worth the impact extra complexity places on all other users.
 
 Rien.
 
>> 
>> 
>> ___
>> 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


Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-15 Thread Adrian Zubarev via swift-evolution
A short example where I personally wanted a public-but-not-open protocol:

public protocol SubscriptParameterType {
 
// This property was needed to prevent the client from breaking
// the library by conforming to the protocol, but I'd like to  
// keep it invisible for the client, or even better prevent the
// client from conforming to the protocol.
var parameter: Document.SubscriptParameter { get }
}

extension Document {
 
public enum SubscriptParameter {
 
case string(String)
case integer(Int)
}
}

extension String : SubscriptParameterType {
 
public var parameter: Document.SubscriptParameter {
 
return .string(self)
}
}

extension Int : SubscriptParameterType {
 
public var parameter: Document.SubscriptParameter {
 
return .integer(self)
}
}

// Somewhere inside the `Document` type
public subscript(firstKey: String, parameters: SubscriptParameterType...) -> 
Value? { … }
That implementation enables more safe queries of my Document type like 
document["key1", intIndexInstance, stringKeyInstance, 10, "key"] rather than 
document["key1/\(intIndexInstance)/\(stringKeyInstance)/10/key"].



-- 
Adrian Zubarev
Sent with Airmail

Am 15. Februar 2017 um 17:03:32, Matthew Johnson via swift-evolution 
(swift-evolution@swift.org) schrieb:


On Feb 15, 2017, at 9:59 AM, Rien  wrote:


On 15 Feb 2017, at 16:45, Matthew Johnson  wrote:


On Feb 15, 2017, at 9:35 AM, Rien  wrote:


On 15 Feb 2017, at 16:11, Matthew Johnson via swift-evolution 
 wrote:


On Feb 15, 2017, at 5:59 AM, Jeremy Pereira via swift-evolution 
 wrote:


On 15 Feb 2017, at 11:11, Brent Royal-Gordon via swift-evolution 
 wrote:


Our philosophy in general, however, is to default to the behavior which 
preserves the most flexibility for the library designer.

Actually, I thought the philosophy was to preserver type safety. When did that 
change?

Also, when was the library designer prioritised ahead of the application 
developer?


Both open and non-open classes are common, but we chose to give non-open 
classes the `public` keyword because that's the flexibility-preserving option.

No it isn’t, it’s the flexibility restricting option. The consumer of an open 
class can subclass it. The consumer of a public class cannot subclass it. How 
is the second more flexible than the first?

It reduces complexity for the library author by allowing them to opt-out of the 
complexity involved in supporting unknown, user-defined subclasses.  It is 
important to allow libraries to have this flexibility. They are free to declare 
a class `open` if they want to allow subclassing. It’s even possibly for a 
library to declare all classes `open` if it wishes to do so.  But *requiring* 
that would reduce the design space libraries are allowed to explore and / or 
introduce fragility by moving the subclass restriction to a comment.


Why would a library author want to prohibit subclasses?
A library user can always wrap the class and subclass the wrapper.

This is composition, not inheritance.  The most important difference is that a 
wrapper cannot override methods, it can only wrap and / or forward them.  This 
means that when the superclass calls a method on `self` that method *always* 
invokes its version of that method rather than a subclass override.  This is a 
very important difference.


Agreed, however that does not answer the question why would a library developer 
want to disallow subclassing?
I do not see a use case for that. I.e. a feature that cannot be implemented 
without it. (without “open”)

The feature it enables is more robust libraries and the ability for library 
authors to better reason about their code.  You may not find this benefit 
enough to be worth a language feature, but many of us do.


Rien.


There are cases where subclassing does not make sense. And thus preventing 
subclasses adds information for those users that don’t RTFM. But that imo is 
not worth the impact extra complexity places on all other users.

Rien.



___
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


Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-15 Thread Matthew Johnson via swift-evolution

> On Feb 15, 2017, at 9:59 AM, Rien  wrote:
> 
>> 
>> On 15 Feb 2017, at 16:45, Matthew Johnson  wrote:
>> 
>>> 
>>> On Feb 15, 2017, at 9:35 AM, Rien  wrote:
>>> 
>>> 
 On 15 Feb 2017, at 16:11, Matthew Johnson via swift-evolution 
  wrote:
 
 
> On Feb 15, 2017, at 5:59 AM, Jeremy Pereira via swift-evolution 
>  wrote:
> 
> 
>> On 15 Feb 2017, at 11:11, Brent Royal-Gordon via swift-evolution 
>>  wrote:
>> 
>> 
>> Our philosophy in general, however, is to default to the behavior which 
>> preserves the most flexibility for the library designer.
> 
> Actually, I thought the philosophy was to preserver type safety. When did 
> that change?
> 
> Also, when was the library designer prioritised ahead of the application 
> developer?
> 
> 
>> Both open and non-open classes are common, but we chose to give non-open 
>> classes the `public` keyword because that's the flexibility-preserving 
>> option.
> 
> No it isn’t, it’s the flexibility restricting option. The consumer of an 
> open class can subclass it. The consumer of a public class cannot 
> subclass it. How is the second more flexible than the first?
 
 It reduces complexity for the library author by allowing them to opt-out 
 of the complexity involved in supporting unknown, user-defined subclasses. 
  It is important to allow libraries to have this flexibility. They are 
 free to declare a class `open` if they want to allow subclassing. It’s 
 even possibly for a library to declare all classes `open` if it wishes to 
 do so.  But *requiring* that would reduce the design space libraries are 
 allowed to explore and / or introduce fragility by moving the subclass 
 restriction to a comment.
 
>>> 
>>> Why would a library author want to prohibit subclasses?
>>> A library user can always wrap the class and subclass the wrapper.
>> 
>> This is composition, not inheritance.  The most important difference is that 
>> a wrapper cannot override methods, it can only wrap and / or forward them.  
>> This means that when the superclass calls a method on `self` that method 
>> *always* invokes its version of that method rather than a subclass override. 
>>  This is a very important difference.
>> 
> 
> Agreed, however that does not answer the question why would a library 
> developer want to disallow subclassing?
> I do not see a use case for that. I.e. a feature that cannot be implemented 
> without it. (without “open”)

The feature it enables is more robust libraries and the ability for library 
authors to better reason about their code.  You may not find this benefit 
enough to be worth a language feature, but many of us do.

> 
> Rien.
> 
>>> 
>>> There are cases where subclassing does not make sense. And thus preventing 
>>> subclasses adds information for those users that don’t RTFM. But that imo 
>>> is not worth the impact extra complexity places on all other users.
>>> 
>>> Rien.
>>> 
> 
> 
> ___
> 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


Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-15 Thread Rien via swift-evolution

> On 15 Feb 2017, at 16:45, Matthew Johnson  wrote:
> 
>> 
>> On Feb 15, 2017, at 9:35 AM, Rien  wrote:
>> 
>> 
>>> On 15 Feb 2017, at 16:11, Matthew Johnson via swift-evolution 
>>>  wrote:
>>> 
>>> 
 On Feb 15, 2017, at 5:59 AM, Jeremy Pereira via swift-evolution 
  wrote:
 
 
> On 15 Feb 2017, at 11:11, Brent Royal-Gordon via swift-evolution 
>  wrote:
> 
> 
> Our philosophy in general, however, is to default to the behavior which 
> preserves the most flexibility for the library designer.
 
 Actually, I thought the philosophy was to preserver type safety. When did 
 that change?
 
 Also, when was the library designer prioritised ahead of the application 
 developer?
 
 
> Both open and non-open classes are common, but we chose to give non-open 
> classes the `public` keyword because that's the flexibility-preserving 
> option.
 
 No it isn’t, it’s the flexibility restricting option. The consumer of an 
 open class can subclass it. The consumer of a public class cannot subclass 
 it. How is the second more flexible than the first?
>>> 
>>> It reduces complexity for the library author by allowing them to opt-out of 
>>> the complexity involved in supporting unknown, user-defined subclasses.  It 
>>> is important to allow libraries to have this flexibility. They are free to 
>>> declare a class `open` if they want to allow subclassing.  It’s even 
>>> possibly for a library to declare all classes `open` if it wishes to do so. 
>>>  But *requiring* that would reduce the design space libraries are allowed 
>>> to explore and / or introduce fragility by moving the subclass restriction 
>>> to a comment.
>>> 
>> 
>> Why would a library author want to prohibit subclasses?
>> A library user can always wrap the class and subclass the wrapper.
> 
> This is composition, not inheritance.  The most important difference is that 
> a wrapper cannot override methods, it can only wrap and / or forward them.  
> This means that when the superclass calls a method on `self` that method 
> *always* invokes its version of that method rather than a subclass override.  
> This is a very important difference.
> 

Agreed, however that does not answer the question why would a library developer 
want to disallow subclassing?
I do not see a use case for that. I.e. a feature that cannot be implemented 
without it. (without “open”)

Rien.

>> 
>> There are cases where subclassing does not make sense. And thus preventing 
>> subclasses adds information for those users that don’t RTFM. But that imo is 
>> not worth the impact extra complexity places on all other users.
>> 
>> Rien.
>> 
 
 
 ___
 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


Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-15 Thread Matthew Johnson via swift-evolution

> On Feb 15, 2017, at 9:35 AM, Rien  wrote:
> 
> 
>> On 15 Feb 2017, at 16:11, Matthew Johnson via swift-evolution 
>>  wrote:
>> 
>> 
>>> On Feb 15, 2017, at 5:59 AM, Jeremy Pereira via swift-evolution 
>>>  wrote:
>>> 
>>> 
 On 15 Feb 2017, at 11:11, Brent Royal-Gordon via swift-evolution 
  wrote:
 
 
 Our philosophy in general, however, is to default to the behavior which 
 preserves the most flexibility for the library designer.
>>> 
>>> Actually, I thought the philosophy was to preserver type safety. When did 
>>> that change?
>>> 
>>> Also, when was the library designer prioritised ahead of the application 
>>> developer?
>>> 
>>> 
 Both open and non-open classes are common, but we chose to give non-open 
 classes the `public` keyword because that's the flexibility-preserving 
 option.
>>> 
>>> No it isn’t, it’s the flexibility restricting option. The consumer of an 
>>> open class can subclass it. The consumer of a public class cannot subclass 
>>> it. How is the second more flexible than the first?
>> 
>> It reduces complexity for the library author by allowing them to opt-out of 
>> the complexity involved in supporting unknown, user-defined subclasses.  It 
>> is important to allow libraries to have this flexibility.  They are free to 
>> declare a class `open` if they want to allow subclassing.  It’s even 
>> possibly for a library to declare all classes `open` if it wishes to do so.  
>> But *requiring* that would reduce the design space libraries are allowed to 
>> explore and / or introduce fragility by moving the subclass restriction to a 
>> comment.
>> 
> 
> Why would a library author want to prohibit subclasses?
> A library user can always wrap the class and subclass the wrapper.

This is composition, not inheritance.  The most important difference is that a 
wrapper cannot override methods, it can only wrap and / or forward them.  This 
means that when the superclass calls a method on `self` that method *always* 
invokes its version of that method rather than a subclass override.  This is a 
very important difference.

> 
> There are cases where subclassing does not make sense. And thus preventing 
> subclasses adds information for those users that don’t RTFM. But that imo is 
> not worth the impact extra complexity places on all other users.
> 
> Rien.
> 
>>> 
>>> 
>>> ___
>>> 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


Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-15 Thread Rien via swift-evolution

> On 15 Feb 2017, at 16:11, Matthew Johnson via swift-evolution 
>  wrote:
> 
> 
>> On Feb 15, 2017, at 5:59 AM, Jeremy Pereira via swift-evolution 
>>  wrote:
>> 
>> 
>>> On 15 Feb 2017, at 11:11, Brent Royal-Gordon via swift-evolution 
>>>  wrote:
>>> 
>>> 
>>> Our philosophy in general, however, is to default to the behavior which 
>>> preserves the most flexibility for the library designer.
>> 
>> Actually, I thought the philosophy was to preserver type safety. When did 
>> that change?
>> 
>> Also, when was the library designer prioritised ahead of the application 
>> developer?
>> 
>> 
>>> Both open and non-open classes are common, but we chose to give non-open 
>>> classes the `public` keyword because that's the flexibility-preserving 
>>> option.
>> 
>> No it isn’t, it’s the flexibility restricting option. The consumer of an 
>> open class can subclass it. The consumer of a public class cannot subclass 
>> it. How is the second more flexible than the first?
> 
> It reduces complexity for the library author by allowing them to opt-out of 
> the complexity involved in supporting unknown, user-defined subclasses.  It 
> is important to allow libraries to have this flexibility.  They are free to 
> declare a class `open` if they want to allow subclassing.  It’s even possibly 
> for a library to declare all classes `open` if it wishes to do so.  But 
> *requiring* that would reduce the design space libraries are allowed to 
> explore and / or introduce fragility by moving the subclass restriction to a 
> comment.
> 

Why would a library author want to prohibit subclasses?
A library user can always wrap the class and subclass the wrapper.

There are cases where subclassing does not make sense. And thus preventing 
subclasses adds information for those users that don’t RTFM. But that imo is 
not worth the impact extra complexity places on all other users.

Rien.

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


Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-15 Thread Matthew Johnson via swift-evolution

> On Feb 15, 2017, at 5:59 AM, Jeremy Pereira via swift-evolution 
>  wrote:
> 
> 
>> On 15 Feb 2017, at 11:11, Brent Royal-Gordon via swift-evolution 
>>  wrote:
>> 
>> 
>> Our philosophy in general, however, is to default to the behavior which 
>> preserves the most flexibility for the library designer.
> 
> Actually, I thought the philosophy was to preserver type safety. When did 
> that change?
> 
> Also, when was the library designer prioritised ahead of the application 
> developer?
> 
> 
>> Both open and non-open classes are common, but we chose to give non-open 
>> classes the `public` keyword because that's the flexibility-preserving 
>> option.
> 
> No it isn’t, it’s the flexibility restricting option. The consumer of an open 
> class can subclass it. The consumer of a public class cannot subclass it. How 
> is the second more flexible than the first?

It reduces complexity for the library author by allowing them to opt-out of the 
complexity involved in supporting unknown, user-defined subclasses.  It is 
important to allow libraries to have this flexibility.  They are free to 
declare a class `open` if they want to allow subclassing.  It’s even possibly 
for a library to declare all classes `open` if it wishes to do so.  But 
*requiring* that would reduce the design space libraries are allowed to explore 
and / or introduce fragility by moving the subclass restriction to a comment.

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


Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-15 Thread Matthew Johnson via swift-evolution

> On Feb 15, 2017, at 5:52 AM, Jeremy Pereira  
> wrote:
> 
> 
>> On 15 Feb 2017, at 02:16, Xiaodi Wu via swift-evolution 
>>  wrote:
>> 
>> So, perhaps I'm being simplistic here, but--
>> 
>> At the end of the day, aren't we simply trying to enable a resiliency 
>> feature? Could it not be said that an enum where future added cases aren't 
>> source-breaking is a more resilient enum?
>> 
>> Since there is consensus that the status quo is desirable for a lot of use 
>> cases, couldn't we keep spelling it "public enum" and just spell this 
>> proposed more resilient enum "@resilient public enum”?
> 
> If it’s got to be done, this is the best solution, but to my mind, it 
> shouldn’t be done at all. 
> 
> There is no way that a library designer can possibly determine what 
> constitutes “resilient” behaviour on the part of the client software. Maybe 
> adding a default clause is the right thing, but maybe the default clause does 
> something that it shouldn’t for some new enumeration cases. As the client 
> software designer, my only defence is an exhaustive switch statement that 
> relies on the compiler to tell me the it is no longer exhaustive. Yes, it 
> means software in the field will crash until I distribute a new version but 
> that is often preferable to other silent consequences. I really do not want 
> to be forced to add a default to a switch that might reduce the safety of my 
> software.
> 
> Adding new cases to any enumeration where the client software is meant to 
> take different actions based on the different cases is source breaking. End 
> of story. No point in trying to mark them as resilient.
> 
> Adding cases to enumerations that are meant to be passed in to the library 
> e.g. an enumeration that specifies a compositing operation or a string 
> encoding may well not be source breaking (how can you tell in every case?) 
> but it’s unlikely that the client is going to be testing those enumerations 
> in a switch statement anyway.

In order to support adding cases to enums meant to be passed in to a library we 
have to introduce some kind of syntax to distinguish these enums from enums 
that are not resilient.  We’ve been discussing options for how to do this.

> 
> 
> 
>> On Tue, Feb 14, 2017 at 10:09 Matthew Johnson via swift-evolution 
>>  wrote:
>> 
>>> On Feb 14, 2017, at 3:43 AM, Brent Royal-Gordon  
>>> wrote:
>>> 
 On Feb 13, 2017, at 7:45 AM, Matthew Johnson  
 wrote:
 
 If you look closely, when most people say “closed enum” they mean a fixed, 
 complete set of cases that are all public.  But when people say “closed 
 protocol” they don’t actually mean a fixed, complete set of conformances 
 that are all public.  They simply mean clients cannot add conformances.  
 This is the semantic contract of resilient enums, not closed enums.
>>> 
>>> Yes, our traditional terminology here has been a little bit confused.
>>> 
> What I instead suggest is that we think of a closed enum as being like a 
> fragile (non-resilient) struct. In both cases, you are committing to a 
> particular design for the type. So I think we should give them both the 
> same keyword—something like:
> 
>@fixed struct Person {
>var name: String
>var birthDate: Date
>}
>@fixed enum Edge {
>case start
>case end
>}
> 
 
 You omitted public here.  Does that mean you intend for `@fixed` to imply 
 public visibility?  If so, I could get behind this.  But I am curious why 
 you made it an attribute rather than a keyword.
>>> 
>>> No, I'm sorry, I meant to say `@fixed public struct` and `@fixed public 
>>> enum`. I don't think `@fixed` implies public-ness, either, so it would need 
>>> to be paired with a `public` keyword. There *may* be keywords we could use 
>>> that would, like `exposed`
>> 
>> I agree that `fixed` (and `closed`) don’t imply `public` in terms of the 
>> colloquial meaning of the words and there is a reasonable case that `open` 
>> does.  I’m not sure I like `exposed`, but maybe it’s possible to find a 
>> keyword that would more directly imply `public`.
>> 
>>> , but I'm not sure we want to make this feature so prominent,
>> 
>> I have some trouble getting on board with requiring an annotation *in 
>> addition* to `public` for the reasons I have already stated, and which led 
>> to `open` becoming an access modifier rather than an annotation.  It’s 
>> possible I could be convinced otherwise, but I think it would require data 
>> showing that this really is a rare edge case.  If the relatively frequency 
>> of closed vs resilient enums is reasonably similar to the relative frequency 
>> of public vs open enums I think there is a strong case to make them carry 
>> the same syntactic weight, as we did 

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-15 Thread Matthew Johnson via swift-evolution

> On Feb 15, 2017, at 5:11 AM, Brent Royal-Gordon  
> wrote:
> 
>> On Feb 14, 2017, at 6:16 PM, Xiaodi Wu  wrote:
>> 
>> So, perhaps I'm being simplistic here, but--
>> 
>> At the end of the day, aren't we simply trying to enable a resiliency 
>> feature? Could it not be said that an enum where future added cases aren't 
>> source-breaking is a more resilient enum?
>> 
>> Since there is consensus that the status quo is desirable for a lot of use 
>> cases, couldn't we keep spelling it "public enum" and just spell this 
>> proposed more resilient enum "@resilient public enum"?
> 
> Our philosophy in general, however, is to default to the behavior which 
> preserves the most flexibility for the library designer. Both open and 
> non-open classes are common, but we chose to give non-open classes the 
> `public` keyword because that's the flexibility-preserving option. Resilient 
> enums are definitely the more flexible option, so by that rule, they should 
> have plain `public`.
> 
> I think that, if enums were a brand-new feature being introduced for the 
> first time in Swift 4, there would be no question that `public enum` ought to 
> give you a resilient enum. The only good reason not to do that is source 
> compatibility. So we need to decide: Which of these principles is more 
> important to us?
> 
> 1. "Defaults for public symbols should preserve as much flexibility for 
> designers as possible."
> 
> 2. "Swift 3 code should compile in Swift 4 without deprecation warnings, 
> unmodified and without a version compatibility flag, whenever possible.”

It’s also worth re-iterating the point I have made about inconsistent semantics 
for `public`, and that this problem as well as your first point also impacts 
protocols.  That means we have two reasons to make a change and both impact 
protocols and enums.  We also have a very reasonable way to introduce the 
changes necessary to solve these problems.

I think the changes are worth making, and certainly worthy of at least bringing 
a proposal to review.

> 
> -- 
> Brent Royal-Gordon
> Architechies
> 

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


Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-15 Thread Jeremy Pereira via swift-evolution

> On 15 Feb 2017, at 11:11, Brent Royal-Gordon via swift-evolution 
>  wrote:
> 
> 
> Our philosophy in general, however, is to default to the behavior which 
> preserves the most flexibility for the library designer.

Actually, I thought the philosophy was to preserver type safety. When did that 
change?

Also, when was the library designer prioritised ahead of the application 
developer?


> Both open and non-open classes are common, but we chose to give non-open 
> classes the `public` keyword because that's the flexibility-preserving option.

No it isn’t, it’s the flexibility restricting option. The consumer of an open 
class can subclass it. The consumer of a public class cannot subclass it. How 
is the second more flexible than the first?


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


Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-15 Thread Jeremy Pereira via swift-evolution

> On 15 Feb 2017, at 02:16, Xiaodi Wu via swift-evolution 
>  wrote:
> 
> So, perhaps I'm being simplistic here, but--
> 
> At the end of the day, aren't we simply trying to enable a resiliency 
> feature? Could it not be said that an enum where future added cases aren't 
> source-breaking is a more resilient enum?
> 
> Since there is consensus that the status quo is desirable for a lot of use 
> cases, couldn't we keep spelling it "public enum" and just spell this 
> proposed more resilient enum "@resilient public enum”?

If it’s got to be done, this is the best solution, but to my mind, it shouldn’t 
be done at all. 

There is no way that a library designer can possibly determine what constitutes 
“resilient” behaviour on the part of the client software. Maybe adding a 
default clause is the right thing, but maybe the default clause does something 
that it shouldn’t for some new enumeration cases. As the client software 
designer, my only defence is an exhaustive switch statement that relies on the 
compiler to tell me the it is no longer exhaustive. Yes, it means software in 
the field will crash until I distribute a new version but that is often 
preferable to other silent consequences. I really do not want to be forced to 
add a default to a switch that might reduce the safety of my software.

Adding new cases to any enumeration where the client software is meant to take 
different actions based on the different cases is source breaking. End of 
story. No point in trying to mark them as resilient.

Adding cases to enumerations that are meant to be passed in to the library e.g. 
an enumeration that specifies a compositing operation or a string encoding may 
well not be source breaking (how can you tell in every case?) but it’s unlikely 
that the client is going to be testing those enumerations in a switch statement 
anyway.



> On Tue, Feb 14, 2017 at 10:09 Matthew Johnson via swift-evolution 
>  wrote:
> 
> > On Feb 14, 2017, at 3:43 AM, Brent Royal-Gordon  
> > wrote:
> >
> >> On Feb 13, 2017, at 7:45 AM, Matthew Johnson  
> >> wrote:
> >>
> >> If you look closely, when most people say “closed enum” they mean a fixed, 
> >> complete set of cases that are all public.  But when people say “closed 
> >> protocol” they don’t actually mean a fixed, complete set of conformances 
> >> that are all public.  They simply mean clients cannot add conformances.  
> >> This is the semantic contract of resilient enums, not closed enums.
> >
> > Yes, our traditional terminology here has been a little bit confused.
> >
> >>> What I instead suggest is that we think of a closed enum as being like a 
> >>> fragile (non-resilient) struct. In both cases, you are committing to a 
> >>> particular design for the type. So I think we should give them both the 
> >>> same keyword—something like:
> >>>
> >>> @fixed struct Person {
> >>> var name: String
> >>> var birthDate: Date
> >>> }
> >>> @fixed enum Edge {
> >>> case start
> >>> case end
> >>> }
> >>>
> >>
> >> You omitted public here.  Does that mean you intend for `@fixed` to imply 
> >> public visibility?  If so, I could get behind this.  But I am curious why 
> >> you made it an attribute rather than a keyword.
> >
> > No, I'm sorry, I meant to say `@fixed public struct` and `@fixed public 
> > enum`. I don't think `@fixed` implies public-ness, either, so it would need 
> > to be paired with a `public` keyword. There *may* be keywords we could use 
> > that would, like `exposed`
> 
> I agree that `fixed` (and `closed`) don’t imply `public` in terms of the 
> colloquial meaning of the words and there is a reasonable case that `open` 
> does.  I’m not sure I like `exposed`, but maybe it’s possible to find a 
> keyword that would more directly imply `public`.
> 
> > , but I'm not sure we want to make this feature so prominent,
> 
> I have some trouble getting on board with requiring an annotation *in 
> addition* to `public` for the reasons I have already stated, and which led to 
> `open` becoming an access modifier rather than an annotation.  It’s possible 
> I could be convinced otherwise, but I think it would require data showing 
> that this really is a rare edge case.  If the relatively frequency of closed 
> vs resilient enums is reasonably similar to the relative frequency of public 
> vs open enums I think there is a strong case to make them carry the same 
> syntactic weight, as we did with `open`.
> 
> > and I'm not sure how that would work with classes you want to both expose 
> > and permit subclassing of. (Would that be `exposed open class Foo`?)
> 
> 
> Can you elaborate on what you mean by "classes you want to both expose and 
> permit subclassing of”?  Do you mean commit to the set of fields being fixed 
> like you indicated with a struct?  If so, I’m not sure that is a valuable 
> 

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-15 Thread Brent Royal-Gordon via swift-evolution
> On Feb 14, 2017, at 6:16 PM, Xiaodi Wu  wrote:
> 
> So, perhaps I'm being simplistic here, but--
> 
> At the end of the day, aren't we simply trying to enable a resiliency 
> feature? Could it not be said that an enum where future added cases aren't 
> source-breaking is a more resilient enum?
> 
> Since there is consensus that the status quo is desirable for a lot of use 
> cases, couldn't we keep spelling it "public enum" and just spell this 
> proposed more resilient enum "@resilient public enum"?

Our philosophy in general, however, is to default to the behavior which 
preserves the most flexibility for the library designer. Both open and non-open 
classes are common, but we chose to give non-open classes the `public` keyword 
because that's the flexibility-preserving option. Resilient enums are 
definitely the more flexible option, so by that rule, they should have plain 
`public`.

I think that, if enums were a brand-new feature being introduced for the first 
time in Swift 4, there would be no question that `public enum` ought to give 
you a resilient enum. The only good reason not to do that is source 
compatibility. So we need to decide: Which of these principles is more 
important to us?

1. "Defaults for public symbols should preserve as much flexibility for 
designers as possible."

2. "Swift 3 code should compile in Swift 4 without deprecation warnings, 
unmodified and without a version compatibility flag, whenever possible."

-- 
Brent Royal-Gordon
Architechies

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


Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-14 Thread Xiaodi Wu via swift-evolution
So, perhaps I'm being simplistic here, but--

At the end of the day, aren't we simply trying to enable a resiliency
feature? Could it not be said that an enum where future added cases aren't
source-breaking is a more resilient enum?

Since there is consensus that the status quo is desirable for a lot of use
cases, couldn't we keep spelling it "public enum" and just spell this
proposed more resilient enum "@resilient public enum"?
On Tue, Feb 14, 2017 at 10:09 Matthew Johnson via swift-evolution <
swift-evolution@swift.org> wrote:

>
> > On Feb 14, 2017, at 3:43 AM, Brent Royal-Gordon 
> wrote:
> >
> >> On Feb 13, 2017, at 7:45 AM, Matthew Johnson 
> wrote:
> >>
> >> If you look closely, when most people say “closed enum” they mean a
> fixed, complete set of cases that are all public.  But when people say
> “closed protocol” they don’t actually mean a fixed, complete set of
> conformances that are all public.  They simply mean clients cannot add
> conformances.  This is the semantic contract of resilient enums, not closed
> enums.
> >
> > Yes, our traditional terminology here has been a little bit confused.
> >
> >>> What I instead suggest is that we think of a closed enum as being like
> a fragile (non-resilient) struct. In both cases, you are committing to a
> particular design for the type. So I think we should give them both the
> same keyword—something like:
> >>>
> >>> @fixed struct Person {
> >>> var name: String
> >>> var birthDate: Date
> >>> }
> >>> @fixed enum Edge {
> >>> case start
> >>> case end
> >>> }
> >>>
> >>
> >> You omitted public here.  Does that mean you intend for `@fixed` to
> imply public visibility?  If so, I could get behind this.  But I am curious
> why you made it an attribute rather than a keyword.
> >
> > No, I'm sorry, I meant to say `@fixed public struct` and `@fixed public
> enum`. I don't think `@fixed` implies public-ness, either, so it would need
> to be paired with a `public` keyword. There *may* be keywords we could use
> that would, like `exposed`
>
> I agree that `fixed` (and `closed`) don’t imply `public` in terms of the
> colloquial meaning of the words and there is a reasonable case that `open`
> does.  I’m not sure I like `exposed`, but maybe it’s possible to find a
> keyword that would more directly imply `public`.
>
> > , but I'm not sure we want to make this feature so prominent,
>
> I have some trouble getting on board with requiring an annotation *in
> addition* to `public` for the reasons I have already stated, and which led
> to `open` becoming an access modifier rather than an annotation.  It’s
> possible I could be convinced otherwise, but I think it would require data
> showing that this really is a rare edge case.  If the relatively frequency
> of closed vs resilient enums is reasonably similar to the relative
> frequency of public vs open enums I think there is a strong case to make
> them carry the same syntactic weight, as we did with `open`.
>
> > and I'm not sure how that would work with classes you want to both
> expose and permit subclassing of. (Would that be `exposed open class Foo`?)
>
>
> Can you elaborate on what you mean by "classes you want to both expose and
> permit subclassing of”?  Do you mean commit to the set of fields being
> fixed like you indicated with a struct?  If so, I’m not sure that is a
> valuable combination and my instinct is to ban it.
>
> If we did want to support something like that it points to keeping
> `closed` (as in cases, subclasses and conformances) orthogonal to `fixed`
> (as in the set of stored properties).
>
> >
> >>> I don't see it mentioned here (maybe I just missed it), but even
> though we *could* do exhaustiveness checking on non-open protocols, I'm not
> convinced that's a good idea. Usually when you have several types
> conforming to a protocol, you should access type-specific behavior through
> polymorphism, not by switching on the protocol. A protocol is supposed to
> represent a behavior, not just mark a type in some arbitrary way.
> >>
> >> I agree that you should usually be adding polymorphism, but preventing
> exhaustive switch on what is effectively a style argument seems like an
> unnecessary restriction to me.  There will be times when it could be used
> to good effect.  I think the community has done a pretty good job of
> figuring out how to use Swift’s many features well and don’t believe it
> would be frequently abused.
> >
> > I agree we shouldn't change the language to *prevent* bad style. But
> this would go beyond that—we'd be putting specific engineering effort
> solely into *enabling* bad style. At minimum, this should fall so far down
> our to-do list that we'll probably never get to it.
>
> This assumes that switching over conforming types is bad style.  One of
> the biggest problems with switching over subclasses or conforming types is
> the fact that you don’t get 

Re: [swift-evolution] [Pitch] consistent public access modifiers - enums

2017-02-14 Thread Jordan Rose via swift-evolution
Hi, Matthew. Sorry for the delay in sending my second message. As stated before:

> I'm going to break my feedback up into separate messages, because I think 
> really the enum and protocol cases are unrelated. Open classes refer to 
> classes that can be subclassed from clients of the current module, and 
> similarly open protocols would be protocols that can be adopted from clients 
> of the current module. Public-but-not-open classes cannot be subclassed from 
> outside the current module, but they can still be subclassed within the 
> module. By contrast, "open" enums can grow new cases in new versions of the 
> library, but clients still can't add cases. (That's not a totally 
> unreasonable feature to ever consider, but it's not the one we need now.)


This message will talk about enums; the one about protocols (and classes) has 
been sent out already.

Right. So, distinguishing between "enums that have exactly this set of cases 
forever" and other enums is critically important; as has been noted in both bug 
reports and on this list, not doing this has a number of problems:

- For imported enums, init(rawValue:) never produces 'nil', because who knows 
how anyone's using C enums anyway?
- "Exhaustive" switches over imported enums may not have default cases, or 
check for "private cases" defined outside the original enum declaration
- Adding a new case to a Swift enum in a library breaks any client code that 
was trying to switch over it.

At the same time, we really like our exhaustive switches, especially over enums 
we define ourselves. And there's a performance side to this whole thing too; if 
all cases of an enum are known, it can be passed around much more efficiently 
than if it might suddenly grow a new case containing a struct with 5000 Strings 
in it.

I think there's certain behavior that is probably not terribly controversial:

- When enums are imported from Apple frameworks, they should always be "open", 
except for a few exceptions like NSRectEdge. (It's Apple's job to handle this 
and get it right, but if we get it wrong with an imported enum there's still 
the workaround of dropping down to the raw value.)
- When I define Swift enums in the current framework, there's obviously no 
compatibility issues; we should treat them as "closed".

Everything else falls somewhere in the middle, both for enums defined in 
Objective-C:

- If I define an Objective-C enum in the current framework, should it be 
"closed", because there are no compatibility issues, or "open", because there 
could still be private cases defined in a .m file?
- If there's an Objective-C enum in another framework (that I built locally 
with Xcode, Carthage, CocoaPods, SwiftPM, etc.), should it be "closed", because 
there are no binary compatibility issues, or "open", because there may be 
source compatibility issues? We'd really like adding a new enum case to not be 
a breaking change even at the source level.
- If there's an Objective-C enum coming in through a bridging header, should it 
be "closed", because I might have defined it myself, or "open", because it 
might be non-modular content I've used the bridging header to import?

And in Swift:

- If there's a Swift enum in another framework I built locally, should it be 
"closed", because there are no binary compatibility issues, or "open", because 
there may be source compatibility issues? We'd really like adding a new enum 
case to not be a breaking change even at the source level.

Let's now flip this to the other side of the equation. All this talk of 
exhaustiveness mostly just affects 'switch' statements, and possibly the 
behavior of the synthesized 'init(rawValue:)' for imported enums. If an enum is 
"open", that implies you must have a 'default' in a switch. In previous 
(in-person) discussions about this feature, it's been pointed out that the code 
in an otherwise-fully-covered switch is, by definition, unreachable, and 
therefore untestable. This also isn't a desirable situation to be in, but it's 
mitigated somewhat by the fact that there probably aren't many "open" enums you 
should exhaustively switch over anyway. (Think about Apple's frameworks again.)

For people who like exhaustive switches, we thought about adding a new kind of 
'default'—let's call it 'unknownCase' just to be able to talk about it. This 
lets you get warnings when you update to a new SDK, but is even more likely to 
be untested code.

One last problem: I started at the very top by saying why I think "open vs. 
non-open classes and protocols" are very different from "open and closed 
enums". Since we've already claimed "open" as an inheritance-related term, I 
think that we should not use it to describe enums. The same applies to 
"closed", since it would be weird for "open" and "closed" to not be opposites. 
I don't have a better term than "exhaustive vs. non-exhaustive" for now, but 
it's not really the enum that's "exhaustive". I'm going to keep using the 
quoted terms "open" 

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-14 Thread Matthew Johnson via swift-evolution

> On Feb 14, 2017, at 3:43 AM, Brent Royal-Gordon  
> wrote:
> 
>> On Feb 13, 2017, at 7:45 AM, Matthew Johnson  wrote:
>> 
>> If you look closely, when most people say “closed enum” they mean a fixed, 
>> complete set of cases that are all public.  But when people say “closed 
>> protocol” they don’t actually mean a fixed, complete set of conformances 
>> that are all public.  They simply mean clients cannot add conformances.  
>> This is the semantic contract of resilient enums, not closed enums.
> 
> Yes, our traditional terminology here has been a little bit confused.
> 
>>> What I instead suggest is that we think of a closed enum as being like a 
>>> fragile (non-resilient) struct. In both cases, you are committing to a 
>>> particular design for the type. So I think we should give them both the 
>>> same keyword—something like:
>>> 
>>> @fixed struct Person {
>>> var name: String
>>> var birthDate: Date
>>> }
>>> @fixed enum Edge {
>>> case start
>>> case end
>>> }
>>> 
>> 
>> You omitted public here.  Does that mean you intend for `@fixed` to imply 
>> public visibility?  If so, I could get behind this.  But I am curious why 
>> you made it an attribute rather than a keyword.
> 
> No, I'm sorry, I meant to say `@fixed public struct` and `@fixed public 
> enum`. I don't think `@fixed` implies public-ness, either, so it would need 
> to be paired with a `public` keyword. There *may* be keywords we could use 
> that would, like `exposed`

I agree that `fixed` (and `closed`) don’t imply `public` in terms of the 
colloquial meaning of the words and there is a reasonable case that `open` 
does.  I’m not sure I like `exposed`, but maybe it’s possible to find a keyword 
that would more directly imply `public`.

> , but I'm not sure we want to make this feature so prominent, 

I have some trouble getting on board with requiring an annotation *in addition* 
to `public` for the reasons I have already stated, and which led to `open` 
becoming an access modifier rather than an annotation.  It’s possible I could 
be convinced otherwise, but I think it would require data showing that this 
really is a rare edge case.  If the relatively frequency of closed vs resilient 
enums is reasonably similar to the relative frequency of public vs open enums I 
think there is a strong case to make them carry the same syntactic weight, as 
we did with `open`.

> and I'm not sure how that would work with classes you want to both expose and 
> permit subclassing of. (Would that be `exposed open class Foo`?)


Can you elaborate on what you mean by "classes you want to both expose and 
permit subclassing of”?  Do you mean commit to the set of fields being fixed 
like you indicated with a struct?  If so, I’m not sure that is a valuable 
combination and my instinct is to ban it.  

If we did want to support something like that it points to keeping `closed` (as 
in cases, subclasses and conformances) orthogonal to `fixed` (as in the set of 
stored properties).

> 
>>> I don't see it mentioned here (maybe I just missed it), but even though we 
>>> *could* do exhaustiveness checking on non-open protocols, I'm not convinced 
>>> that's a good idea. Usually when you have several types conforming to a 
>>> protocol, you should access type-specific behavior through polymorphism, 
>>> not by switching on the protocol. A protocol is supposed to represent a 
>>> behavior, not just mark a type in some arbitrary way.
>> 
>> I agree that you should usually be adding polymorphism, but preventing 
>> exhaustive switch on what is effectively a style argument seems like an 
>> unnecessary restriction to me.  There will be times when it could be used to 
>> good effect.  I think the community has done a pretty good job of figuring 
>> out how to use Swift’s many features well and don’t believe it would be 
>> frequently abused.
> 
> I agree we shouldn't change the language to *prevent* bad style. But this 
> would go beyond that—we'd be putting specific engineering effort solely into 
> *enabling* bad style. At minimum, this should fall so far down our to-do list 
> that we'll probably never get to it.

This assumes that switching over conforming types is bad style.  One of the 
biggest problems with switching over subclasses or conforming types is the fact 
that you don’t get compiler verification of exhaustiveness.  If the language 
supports exhaustive switching for closed classes and protocols this becomes a 
non-issue.

I don’t know of any languages that support a kind of type which supports 
generic and dynamic dispatch as well as exhaustive switch.  It may be 
interesting to have the ability to organize some methods by type (i.e. protocol 
requirements) and other methods by function (i.e. a protocol extension method 
with an exhaustive switch).  

When you have exhaustive switch these are really just two different ways to 
organize 

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-14 Thread Brent Royal-Gordon via swift-evolution
> On Feb 13, 2017, at 7:45 AM, Matthew Johnson  wrote:
> 
> If you look closely, when most people say “closed enum” they mean a fixed, 
> complete set of cases that are all public.  But when people say “closed 
> protocol” they don’t actually mean a fixed, complete set of conformances that 
> are all public.  They simply mean clients cannot add conformances.  This is 
> the semantic contract of resilient enums, not closed enums.

Yes, our traditional terminology here has been a little bit confused.

>> What I instead suggest is that we think of a closed enum as being like a 
>> fragile (non-resilient) struct. In both cases, you are committing to a 
>> particular design for the type. So I think we should give them both the same 
>> keyword—something like:
>> 
>>  @fixed struct Person {
>>  var name: String
>>  var birthDate: Date
>>  }
>>  @fixed enum Edge {
>>  case start
>>  case end
>>  }
>> 
> 
> You omitted public here.  Does that mean you intend for `@fixed` to imply 
> public visibility?  If so, I could get behind this.  But I am curious why you 
> made it an attribute rather than a keyword.

No, I'm sorry, I meant to say `@fixed public struct` and `@fixed public enum`. 
I don't think `@fixed` implies public-ness, either, so it would need to be 
paired with a `public` keyword. There *may* be keywords we could use that 
would, like `exposed`, but I'm not sure we want to make this feature so 
prominent, and I'm not sure how that would work with classes you want to both 
expose and permit subclassing of. (Would that be `exposed open class Foo`?)

>> I don't see it mentioned here (maybe I just missed it), but even though we 
>> *could* do exhaustiveness checking on non-open protocols, I'm not convinced 
>> that's a good idea. Usually when you have several types conforming to a 
>> protocol, you should access type-specific behavior through polymorphism, not 
>> by switching on the protocol. A protocol is supposed to represent a 
>> behavior, not just mark a type in some arbitrary way.
> 
> I agree that you should usually be adding polymorphism, but preventing 
> exhaustive switch on what is effectively a style argument seems like an 
> unnecessary restriction to me.  There will be times when it could be used to 
> good effect.  I think the community has done a pretty good job of figuring 
> out how to use Swift’s many features well and don’t believe it would be 
> frequently abused.

I agree we shouldn't change the language to *prevent* bad style. But this would 
go beyond that—we'd be putting specific engineering effort solely into 
*enabling* bad style. At minimum, this should fall so far down our to-do list 
that we'll probably never get to it.

>> I still support this general approach. One spelling could simply be 
>> `@nonopen`. Although if we don't use `closed`, we could simply use `@closed` 
>> like I suggested—here it really *would* be an antonym to `open`.
> 
> I like the idea of using `@nonopen` for the transitional attribute.  Both 
> because it “removes the openness” that `public protocol` currently implies.  
> In that sense it is probably the most accurate term we could find and it’s 
> also pretty concise.

It also sounds a little bit awkward, which is normally a reason not to use it, 
but perhaps that's actually a good thing in a temporary, transitional keyword.

>>> A similar mult-release strategy would work for migrating public enums.
>> 
>> What is it that needs migrating here? Lack of exhaustiveness checking? It 
>> sounds like we were planning to break that anyway in some fashion.
> 
> Public enums are not currently resilient.  Clients are allowed to switch over 
> them without a `default` clause.  This means that client code will fail to 
> compile in a version of Swift where `public enum` has the resilient contract 
> unless the library changes to adopt closed semantics or the client adds a 
> default case.

My thinking was that, since most existing `public` enums should probably not be 
`@fixed`, we should just change the behavior and let some switch statements 
break.  Most `public` protocols, on the other hand, ought to become `open`, so 
we should flag that change and require an explicit marker like `@nonopen` if 
you really don't want to change over. But I could be convinced otherwise.

-- 
Brent Royal-Gordon
Architechies

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


Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-13 Thread Brent Royal-Gordon via swift-evolution
> On Feb 13, 2017, at 8:14 AM, Adrian Zubarev  
> wrote:
> 
> Is that assumption correct?
> 
> // Module A
> public protocol SQLiteValue {
> init(statement: SQLiteStatement, columnAt index: Int) throws
> func bind(to statement: SQLiteStatement, at index: Int) throws
> }
> 
> // Module B
> protocol SQLiteLoggable : SQLiteValue {
> var logDescription: String { get }
> }
> 
> I could not follow your example there. If SQLiteLoggable is from module B 
> than this should be an error in my opinion. Otherwise open would have less 
> meaning on protocols, because you always could create an empty protocol that 
> has a super public protocol which you’re not allowed to conform to in module 
> B. This would be a silly workaround to being able to conform to it 
> SQLiteValue indirectly without any further requirement like in 
> SQLiteValueConvertible.

The idea is that a type in Module B could not conform to `SQLiteLoggable` 
without also having a valid conformance to `SQLiteValue`—either by taking a 
type Module A conforms to `SQLValue` and retroactively conforming it to 
`SQLiteLoggable`, or by adding a conformance to `SQLiteConvertible` in Module 
B. So this would not be allow you to work around `SQLiteValue`'s non-open-ness.

-- 
Brent Royal-Gordon
Architechies

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


Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-13 Thread Matthew Johnson via swift-evolution

> On Feb 13, 2017, at 11:28 AM, James Froggatt via swift-evolution 
>  wrote:
> 
> Having loosely followed this discussion, the way I'm thinking of ‘closed’ is 
> as a modifier which would let you switch over something from outside the 
> module in which it is declared.
> 
> From outside the declaring module:
> • A closed enum's cases can be exhaustively switched.
> • A closed protocol's conforming types can be exhaustively switched.
> • A closed class's subclasses can be exhaustively switched.
> 
> If this is correct, I can't help but think ‘closed’ is describing something 
> subtly different in each case - picking and choosing the ‘important’ 
> relationship for each type, while protocols already have a subtyping 
> relationship, and it sounds like there's possibility for enum subtyping in 
> the future.
> 
> I'd rather keep ‘open’ (and a potential future ‘closed’) purely describing 
> the subtyping relationship, and have some other means of labelling 
> conformance and cases as switchable.

I am drafting a manifesto-style document regarding value subtyping which will 
make it clear how value subtypes fit into the picture.  This document covers 
the relationship of enum cases with value subtyping and will show clearly how 
enum cases are analogous to subclasses.

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


Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-13 Thread James Froggatt via swift-evolution
Having loosely followed this discussion, the way I'm thinking of ‘closed’ is as 
a modifier which would let you switch over something from outside the module in 
which it is declared.

From outside the declaring module:
• A closed enum's cases can be exhaustively switched.
• A closed protocol's conforming types can be exhaustively switched.
• A closed class's subclasses can be exhaustively switched.

If this is correct, I can't help but think ‘closed’ is describing something 
subtly different in each case - picking and choosing the ‘important’ 
relationship for each type, while protocols already have a subtyping 
relationship, and it sounds like there's possibility for enum subtyping in the 
future.

I'd rather keep ‘open’ (and a potential future ‘closed’) purely describing the 
subtyping relationship, and have some other means of labelling conformance and 
cases as switchable.
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-13 Thread Adrian Zubarev via swift-evolution
Okay thanks, that makes now sense to me. So even if we refine public protocols 
from module A with a custom protocol in module B, there is no way we can 
conform any other type from module B to it, but we could conform existing types 
of module A to our refined protocols.

That’s fine by me, because the consistent restriction of public would remain 
the same. :)



-- 
Adrian Zubarev
Sent with Airmail

Am 13. Februar 2017 um 17:27:36, Matthew Johnson (matt...@anandabits.com) 
schrieb:


On Feb 13, 2017, at 10:14 AM, Adrian Zubarev via swift-evolution 
 wrote:

Is that assumption correct?

// Module A
public protocol SQLiteValue {
init(statement: SQLiteStatement, columnAt index: Int) throws
func bind(to statement: SQLiteStatement, at index: Int) throws
}

// Module B
protocol SQLiteLoggable : SQLiteValue {
var logDescription: String { get }
}
I could not follow your example there. If SQLiteLoggable is from module B than 
this should be an error in my opinion.

Yes, Brent was using `public protocol` with the same semantics that `public 
class` has today (i.e. not open) so this would be an error.

Otherwise open would have less meaning on protocols, because you always could 
create an empty protocol that has a super public protocol which you’re not 
allowed to conform to in module B. This would be a silly workaround to being 
able to conform to it SQLiteValue indirectly without any further requirement 
like in SQLiteValueConvertible.

That said, it makes no sense to me to allow that, because it’s simply a 
workaround to conform to a protocol which public-but-not-open tries to prevent.

// Module X
public protocol A {}

open protocol AA : A { func foo() } // Fine

// Module Y
struct B : A {} // Error
struct B : AA { func foo() { .. } } // Okay
No, `struct B : AA` is an error because in order to conform to `AA`, `B` must 
also conform to `A`, which it cannot because `A` is closed.



protocol C : A {} // Error because `struct B : C` would equal `struct B : A`
No, this is allowed.  However the only types that can conform to `C` are types 
declared in module X that *already* conform to `A`.  They may be extended to 
retroactively conform to `C`.

protocol CC : AA {} // Should work even empty, because we have more requirement 
from `AA`
public should have a consistent meaning across all types from module A in 
module B, which is ‘not allowed to sub-type from’ and in case of protocols 
additionally ‘not allowed to conform to’.

___
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


Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-13 Thread Matthew Johnson via swift-evolution

> On Feb 13, 2017, at 10:14 AM, Adrian Zubarev via swift-evolution 
>  wrote:
> 
> Is that assumption correct?
> 
> // Module A
> public protocol SQLiteValue {
> init(statement: SQLiteStatement, columnAt index: Int) throws
> func bind(to statement: SQLiteStatement, at index: Int) throws
> }
> 
> // Module B
> protocol SQLiteLoggable : SQLiteValue {
> var logDescription: String { get }
> }
> I could not follow your example there. If SQLiteLoggable is from module B 
> than this should be an error in my opinion.
> 
Yes, Brent was using `public protocol` with the same semantics that `public 
class` has today (i.e. not open) so this would be an error.

> Otherwise open would have less meaning on protocols, because you always could 
> create an empty protocol that has a super public protocol which you’re not 
> allowed to conform to in module B. This would be a silly workaround to being 
> able to conform to it SQLiteValue indirectly without any further requirement 
> like in SQLiteValueConvertible.
> 
> That said, it makes no sense to me to allow that, because it’s simply a 
> workaround to conform to a protocol which public-but-not-open tries to 
> prevent.
> 
> // Module X
> public protocol A {}
> 
> open protocol AA : A { func foo() } // Fine
> 
> // Module Y
> struct B : A {} // Error
> struct B : AA { func foo() { .. } } // Okay
No, `struct B : AA` is an error because in order to conform to `AA`, `B` must 
also conform to `A`, which it cannot because `A` is closed.


> 
> protocol C : A {} // Error because `struct B : C` would equal `struct B : A`
No, this is allowed.  However the only types that can conform to `C` are types 
declared in module X that *already* conform to `A`.  They may be extended to 
retroactively conform to `C`.

> protocol CC : AA {} // Should work even empty, because we have more 
> requirement from `AA`
> public should have a consistent meaning across all types from module A in 
> module B, which is ‘not allowed to sub-type from’ and in case of protocols 
> additionally ‘not allowed to conform to’.
> 
> ___
> 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


Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-13 Thread Matthew Johnson via swift-evolution

> On Feb 13, 2017, at 10:19 AM, Karl Wagner  wrote:
> 
>> 
>>> 
>>> As I mentioned earlier, I don't think `closed` is a good keyword standing 
>>> alone. And I also think that, given that we have `open`, `closed` also 
>>> won't pair well with `public`—they sound like antonyms when they aren’t.
>> 
>> The semantics I am proposing do have an inverse relationship.  That said, it 
>> may not be an intuitive or immediately obvious inverse.  I am certainly not 
>> wedded to the idea of using `closed` as the keyword.
>> 
>>> 
>>> What I instead suggest is that we think of a closed enum as being like a 
>>> fragile (non-resilient) struct. In both cases, you are committing to a 
>>> particular design for the type. So I think we should give them both the 
>>> same keyword—something like:
>>> 
>>> @fixed struct Person {
>>> var name: String
>>> var birthDate: Date
>>> }
>>> @fixed enum Edge {
>>> case start
>>> case end
>>> }
>>> 
>> 
> 
> What about “final”?
> 

Final has a very different meaning: this type has no subtypes.___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-13 Thread Karl Wagner via swift-evolution
> 
>> 
>> As I mentioned earlier, I don't think `closed` is a good keyword standing 
>> alone. And I also think that, given that we have `open`, `closed` also won't 
>> pair well with `public`—they sound like antonyms when they aren’t.
> 
> The semantics I am proposing do have an inverse relationship.  That said, it 
> may not be an intuitive or immediately obvious inverse.  I am certainly not 
> wedded to the idea of using `closed` as the keyword.
> 
>> 
>> What I instead suggest is that we think of a closed enum as being like a 
>> fragile (non-resilient) struct. In both cases, you are committing to a 
>> particular design for the type. So I think we should give them both the same 
>> keyword—something like:
>> 
>>  @fixed struct Person {
>>  var name: String
>>  var birthDate: Date
>>  }
>>  @fixed enum Edge {
>>  case start
>>  case end
>>  }
>> 
> 

What about “final”?

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


Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-13 Thread Adrian Zubarev via swift-evolution
Is that assumption correct?

// Module A
public protocol SQLiteValue {
init(statement: SQLiteStatement, columnAt index: Int) throws
func bind(to statement: SQLiteStatement, at index: Int) throws
}

// Module B
protocol SQLiteLoggable : SQLiteValue {
var logDescription: String { get }
}
I could not follow your example there. If SQLiteLoggable is from module B than 
this should be an error in my opinion. Otherwise open would have less meaning 
on protocols, because you always could create an empty protocol that has a 
super public protocol which you’re not allowed to conform to in module B. This 
would be a silly workaround to being able to conform to it SQLiteValue 
indirectly without any further requirement like in SQLiteValueConvertible.

That said, it makes no sense to me to allow that, because it’s simply a 
workaround to conform to a protocol which public-but-not-open tries to prevent.

// Module X
public protocol A {}

open protocol AA : A { func foo() } // Fine

// Module Y
struct B : A {} // Error
struct B : AA { func foo() { .. } } // Okay

protocol C : A {} // Error because `struct B : C` would equal `struct B : A`
protocol CC : AA {} // Should work even empty, because we have more requirement 
from `AA`
public should have a consistent meaning across all types from module A in 
module B, which is ‘not allowed to sub-type from’ and in case of protocols 
additionally ‘not allowed to conform to’.___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-13 Thread Matthew Johnson via swift-evolution

> On Feb 13, 2017, at 8:24 AM, Brent Royal-Gordon  
> wrote:
> 
> Sorry, I meant to jump in a lot earlier than this, but lost track of this 
> thread on my mental to-do list. I've read most of the thread, but I really 
> can't keep all the replies in my head at once, so I apologize if some of this 
> is duplicative.

Hi Brent, no problem!  Thanks for taking time to read it and offer feedback.

> 
> I agree with Jordan Rose that "closed enums" and "closed protocols" are 
> separate things and they should be discussed separately, so I'll be doing 
> that here. But first, a criticism of both:

I agree that they are separate things.  But there is also important semantic 
overlap.  One of the major motivations behind my proposal is that I think we’re 
ignoring this semantic overlap and therefore being sloppy with our terminology. 
 I think it would be wise to consider carefully whether it is a good idea to 
continue ignoring the overlap.  I think one can make an argument that it 
ignoring it is a pragmatic choice, but one can also make an argument that it is 
hand-wavy.  

If you look closely, when most people say “closed enum” they mean a fixed, 
complete set of cases that are all public.  But when people say “closed 
protocol” they don’t actually mean a fixed, complete set of conformances that 
are all public.  They simply mean clients cannot add conformances.  This is the 
semantic contract of resilient enums, not closed enums.

> 
>> On Feb 8, 2017, at 3:05 PM, Matthew Johnson via swift-evolution 
>>  wrote:
>> 
>> This proposal introduces the new access modifier `closed` as well as 
>> clarifying the meaning of `public` and expanding the use of `open`.
> 
> If the `closed` keyword is to stand alone as an access level, I think 
> `closed` is a bad choice. `open` is acceptable because it sounds as visible 
> or even *more* visible than `public`. (AppKit is "public", but GTK is "open". 
> Which exposes more of itself to a programmer?) But `closed` sounds like some 
> form of privacy. I think that, unless it's paired with a word like `public`, 
> it will not be understood correctly.

This certainly is a fair criticism.  `closed` is the term that has been heavily 
used by the community and is an inverse of `open`, which makes sense because it 
is in many respects a semantic inverse.  That said, I would embrace a healthy 
round of bike shedding to try and find a better keyword.

> 
> Closed enums:
> 
>> A recent thread 
>> (https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170206/031566.html)
>>  discussed a similar tradeoff regarding whether public enums should commit 
>> to a fixed set of cases by default or not.  The current behavior is that 
>> they *do* commit to a fixed set of cases and there is no option (afaik) to 
>> modify that behavior.  The Library Evolution document 
>> (https://github.com/apple/swift/blob/master/docs/LibraryEvolution.rst#enums) 
>> suggests a desire to change this before locking down ABI such that public 
>> enums *do not* make this commitment by default, and are required to opt-in 
>> to this behavior using an `@closed` annotation.
>> 
>> In the previous discussion I stated a strong preference that closed enums 
>> *not* be penalized with an additional annotation.  This is because I feel 
>> pretty strongly that it is a design smell to: 1) expose cases publicly if 
>> consumers of the API are not expected to switch on them and 2) require users 
>> to handle unknown future cases if they are likely to switch over the cases 
>> in correct use of the API.
> 
> The thing is, you do *lots* of things with enums other than exhaustively 
> switching on them. One extremely common example is `Error` enums. But even 
> leaving that aside, there are lots of cases where you construct an enum and 
> hand it off to a library to work or interpret it; adding a case won't break 
> these.
> 
> Basically, when an enum is an input to a library, adding cases is safe. When 
> it's an output from a library, adding cases is potentially unsafe, unless the 
> code using the enum is designed to permit additional cases. 

Yes, I agree with this.  I was overreaching a bit in that paragraph.  My point 
is that you can achieve the same client syntax for library inputs using designs 
that don’t expose cases publicly (i.e. discourage users from writing a switch). 
 Maybe, at least in some cases, that is what a library should do.  Saying it 
*is* a design smell was an exaggeration, but saying it is a contract worthy of 
close consideration is accurate.

> 
>> The conclusion I came to in that thread is that we should adopt the same 
>> strategy as we did with classes: there should not be a default.
> 
> But classes *do* have a default: closed, i.e., `public`. It is an extremely 
> soft default, and we've made it as easy as possible to switch to `open`, but 
> `public` is absolutely the default—both because `public` is the keyword 
> people will know 

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-13 Thread Brent Royal-Gordon via swift-evolution
Sorry, I meant to jump in a lot earlier than this, but lost track of this 
thread on my mental to-do list. I've read most of the thread, but I really 
can't keep all the replies in my head at once, so I apologize if some of this 
is duplicative.

I agree with Jordan Rose that "closed enums" and "closed protocols" are 
separate things and they should be discussed separately, so I'll be doing that 
here. But first, a criticism of both:

> On Feb 8, 2017, at 3:05 PM, Matthew Johnson via swift-evolution 
>  wrote:
> 
> This proposal introduces the new access modifier `closed` as well as 
> clarifying the meaning of `public` and expanding the use of `open`.

If the `closed` keyword is to stand alone as an access level, I think `closed` 
is a bad choice. `open` is acceptable because it sounds as visible or even 
*more* visible than `public`. (AppKit is "public", but GTK is "open". Which 
exposes more of itself to a programmer?) But `closed` sounds like some form of 
privacy. I think that, unless it's paired with a word like `public`, it will 
not be understood correctly.

Closed enums:

> A recent thread 
> (https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170206/031566.html)
>  discussed a similar tradeoff regarding whether public enums should commit to 
> a fixed set of cases by default or not.  The current behavior is that they 
> *do* commit to a fixed set of cases and there is no option (afaik) to modify 
> that behavior.  The Library Evolution document 
> (https://github.com/apple/swift/blob/master/docs/LibraryEvolution.rst#enums) 
> suggests a desire to change this before locking down ABI such that public 
> enums *do not* make this commitment by default, and are required to opt-in to 
> this behavior using an `@closed` annotation.
> 
> In the previous discussion I stated a strong preference that closed enums 
> *not* be penalized with an additional annotation.  This is because I feel 
> pretty strongly that it is a design smell to: 1) expose cases publicly if 
> consumers of the API are not expected to switch on them and 2) require users 
> to handle unknown future cases if they are likely to switch over the cases in 
> correct use of the API.

The thing is, you do *lots* of things with enums other than exhaustively 
switching on them. One extremely common example is `Error` enums. But even 
leaving that aside, there are lots of cases where you construct an enum and 
hand it off to a library to work or interpret it; adding a case won't break 
these.

Basically, when an enum is an input to a library, adding cases is safe. When 
it's an output from a library, adding cases is potentially unsafe, unless the 
code using the enum is designed to permit additional cases. 

> The conclusion I came to in that thread is that we should adopt the same 
> strategy as we did with classes: there should not be a default.

But classes *do* have a default: closed, i.e., `public`. It is an extremely 
soft default, and we've made it as easy as possible to switch to `open`, but 
`public` is absolutely the default—both because `public` is the keyword people 
will know from other languages, and because `public` is the term used with 
non-class-related symbols.

And remember, it's the default for a good reason: `public`'s semantic is the 
more forgiving one. If you make a class `public` when it should be `open`, 
fixing it is not a breaking change, but the opposite is.

In the case of enums, public-but-nonexhaustive is the more forgiving semantic. 
If you make something public-but-nonexhaustive when it should be 
public-but-exhaustive, fixing it is not a breaking change, but the opposite is.

As I mentioned earlier, I don't think `closed` is a good keyword standing 
alone. And I also think that, given that we have `open`, `closed` also won't 
pair well with `public`—they sound like antonyms when they aren't.

What I instead suggest is that we think of a closed enum as being like a 
fragile (non-resilient) struct. In both cases, you are committing to a 
particular design for the type. So I think we should give them both the same 
keyword—something like:

@fixed struct Person {
var name: String
var birthDate: Date
}
@fixed enum Edge {
case start
case end
}

As I mentioned in another post, inheriting from an enum is not really a 
sensible thing to do. It is perhaps possible that we could eventually introduce 
`open enum`s, which would permit you to add cases in outside extensions. (That 
might be useful for error enums, but I honestly can't think of many other use 
cases.) But enums would need to gain new features—like member overrides 
attached to cases—to make that useful. All in all, I'm not entirely convinced 
about open enums.

Closed protocols:

> There have also been several discussions both on the list and via Twitter 
> regarding whether or not we should allow closed protocols.  In a 

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-12 Thread Slava Pestov via swift-evolution
Also, note that there will be at least one other similar annotation, but for 
structs — the evolution document calls it @fixedContents. We want a way to 
declare that the set of stored properties in a struct will never change, 
allowing clients to make assumptions about its layout. Unlike @closed enums, 
@fixedContents structs mostly behave the same. The one important difference is 
that it will be possible to define designated initializers of @fixedContents 
structs inside extensions from another module.

Slava

> On Feb 12, 2017, at 8:49 AM, Matthew Johnson via swift-evolution 
>  wrote:
> 
>> 
>> On Feb 12, 2017, at 10:39 AM, Nevin Brackett-Rozinsky via swift-evolution 
>> > wrote:
>> 
>> Alternative: leave “public enum” as it is now, and spell the resilient 
>> version “@resilient enum”
> 
> The problem with this approach is that the “default” is the stricter contract 
> and library authors have to remember to add the annotation to opt-out of that 
> stricter contract.  The problems created by the stricter contract will only 
> appear later when the author realizes they need to add new cases and now it’s 
> a breaking change.  
> 
> Responsible library authors should always make an intentional choice, but 
> sometimes even the best of us make mistakes.  If a library author makes this 
> mistake it is likely that it won’t be noticed until it is too late.  
> Requiring the library author to make a choice between mutually exclusive 
> options rather than a choice to add or omit an annotation reduces the chance 
> of the library author making this error.  
> 
> This is the rationale that led to us adding `open` rather than adding 
> something like an `@closed` annotation for classes.  The desire to avoid 
> growing lots of annotations in the language was also an important 
> consideration that I believe applies here.
> 
>> 
>> Nevin
>> 
>> 
>> On Sunday, February 12, 2017, Matthew Johnson via swift-evolution 
>> > wrote:
>> 
>>> On Feb 12, 2017, at 10:24 AM, David Hart > wrote:
>>> 
>>> 
>>> On 12 Feb 2017, at 16:38, Matthew Johnson > wrote:
>>> 
 
> On Feb 12, 2017, at 12:50 AM, David Hart > wrote:
> 
> Hi Matthew,
> 
> I've read your proposal ideas and most of the discussions on the thread, 
> and I'd like to provide some personal feedback.
> 
> Swift already has a complicated "access modifier" story so I think we 
> really want a good reason to introduce a new one. And the problem I see 
> is that `closed` has much less semantic weight than the other modifiers.
 
 How so?  I’m not sure if I catch your meaning here.  It feels to me like 
 it has the same semantic weight as `open`: prohibiting future versions of 
 a module from adding cases / subclasses / conformances is roughly the 
 inverse of lifting the restriction that clients cannot add those things.  
 Therefore it has roughly the same degree of additional meaning over 
 `public` as `open` does.
>>> 
>>> The difference I see is precisely that 'public' and 'open' modifiers limit 
>>> what the client of a module can do while closed limits what future versions 
>>> of a module can do. Feels quite different to me.
>> 
>> This is a reasonable point and is perhaps the strongest argument made 
>> against my proposal thus far.  However, I think we have to consider my 
>> proposal relative to the alternatives.  
>> 
>> The only alternative I am aware of is making `public enum` the resilient 
>> variety and using `@closed public enum` for the closed variety.  This means 
>> that `public` will have at least two different semantics (three if we don’t 
>> reconcile classes and protocols).  It also means that the resilient variety 
>> is effectively the default.  I am really happy that we decide not to have a 
>> default between `open` and `public` and think the best choice is that we 
>> don’t have one here either.  The fact that we have a way to do this while 
>> solving the inconsistent semantics of `public` feels like a net win to me.
>> 
>>> 
> 
> First of all, the Library Evolution document you linked says toward at 
> the top that "this document is primarily concerned with binary 
> compatibility, i.e. what changes can safely be made to a library between 
> releases that will not break memory-safety or type-safety, or cause 
> clients to fail to run at all." It seems to me that the @closed 
> introduced in that document is much more about library resilience than 
> about only closing down the addition of new cases: that's why it also 
> talks about reordering and all other changes that can change the memory 
> layout.
> 
> Swift 3 having introduced both fileprivate and open has complexified the 
> access level story for 

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-12 Thread Matthew Johnson via swift-evolution

> On Feb 12, 2017, at 10:39 AM, Nevin Brackett-Rozinsky via swift-evolution 
>  wrote:
> 
> Alternative: leave “public enum” as it is now, and spell the resilient 
> version “@resilient enum”

The problem with this approach is that the “default” is the stricter contract 
and library authors have to remember to add the annotation to opt-out of that 
stricter contract.  The problems created by the stricter contract will only 
appear later when the author realizes they need to add new cases and now it’s a 
breaking change.  

Responsible library authors should always make an intentional choice, but 
sometimes even the best of us make mistakes.  If a library author makes this 
mistake it is likely that it won’t be noticed until it is too late.  Requiring 
the library author to make a choice between mutually exclusive options rather 
than a choice to add or omit an annotation reduces the chance of the library 
author making this error.  

This is the rationale that led to us adding `open` rather than adding something 
like an `@closed` annotation for classes.  The desire to avoid growing lots of 
annotations in the language was also an important consideration that I believe 
applies here.

> 
> Nevin
> 
> 
> On Sunday, February 12, 2017, Matthew Johnson via swift-evolution 
> > wrote:
> 
>> On Feb 12, 2017, at 10:24 AM, David Hart > > wrote:
>> 
>> 
>> On 12 Feb 2017, at 16:38, Matthew Johnson > > wrote:
>> 
>>> 
 On Feb 12, 2017, at 12:50 AM, David Hart > wrote:
 
 Hi Matthew,
 
 I've read your proposal ideas and most of the discussions on the thread, 
 and I'd like to provide some personal feedback.
 
 Swift already has a complicated "access modifier" story so I think we 
 really want a good reason to introduce a new one. And the problem I see is 
 that `closed` has much less semantic weight than the other modifiers.
>>> 
>>> How so?  I’m not sure if I catch your meaning here.  It feels to me like it 
>>> has the same semantic weight as `open`: prohibiting future versions of a 
>>> module from adding cases / subclasses / conformances is roughly the inverse 
>>> of lifting the restriction that clients cannot add those things.  Therefore 
>>> it has roughly the same degree of additional meaning over `public` as 
>>> `open` does.
>> 
>> The difference I see is precisely that 'public' and 'open' modifiers limit 
>> what the client of a module can do while closed limits what future versions 
>> of a module can do. Feels quite different to me.
> 
> This is a reasonable point and is perhaps the strongest argument made against 
> my proposal thus far.  However, I think we have to consider my proposal 
> relative to the alternatives.  
> 
> The only alternative I am aware of is making `public enum` the resilient 
> variety and using `@closed public enum` for the closed variety.  This means 
> that `public` will have at least two different semantics (three if we don’t 
> reconcile classes and protocols).  It also means that the resilient variety 
> is effectively the default.  I am really happy that we decide not to have a 
> default between `open` and `public` and think the best choice is that we 
> don’t have one here either.  The fact that we have a way to do this while 
> solving the inconsistent semantics of `public` feels like a net win to me.
> 
>> 
 
 First of all, the Library Evolution document you linked says toward at the 
 top that "this document is primarily concerned with binary compatibility, 
 i.e. what changes can safely be made to a library between releases that 
 will not break memory-safety or type-safety, or cause clients to fail to 
 run at all." It seems to me that the @closed introduced in that document 
 is much more about library resilience than about only closing down the 
 addition of new cases: that's why it also talks about reordering and all 
 other changes that can change the memory layout.
 
 Swift 3 having introduced both fileprivate and open has complexified the 
 access level story for developers and library authors. That complexity is 
 the cost that we have paid for more expressiveness. But if we continue 
 adding new access control modifiers to express new semantics, we may be 
 going too far: perfect is the enemy of good.
 
 Both of those arguments explain why I think closed should be introduced, 
 but only as a rarely-used attribute for library authors which need to 
 express ABI resilience, and not as an extra access modifier.
>>> 
>>> `closed` is about much more than binary compatibility.  Any time a library 
>>> publishes an enum that clients can 

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-12 Thread Nevin Brackett-Rozinsky via swift-evolution
Alternative: leave “public enum” as it is now, and spell the resilient
version “@resilient enum”

Nevin


On Sunday, February 12, 2017, Matthew Johnson via swift-evolution <
swift-evolution@swift.org> wrote:

>
> On Feb 12, 2017, at 10:24 AM, David Hart  > wrote:
>
>
> On 12 Feb 2017, at 16:38, Matthew Johnson  > wrote:
>
>
> On Feb 12, 2017, at 12:50 AM, David Hart  > wrote:
>
> Hi Matthew,
>
> I've read your proposal ideas and most of the discussions on the thread,
> and I'd like to provide some personal feedback.
>
> Swift already has a complicated "access modifier" story so I think we
> really want a good reason to introduce a new one. And the problem I see is
> that `closed` has much less semantic weight than the other modifiers.
>
>
> How so?  I’m not sure if I catch your meaning here.  It feels to me like
> it has the same semantic weight as `open`: prohibiting future versions of a
> module from adding cases / subclasses / conformances is roughly the inverse
> of lifting the restriction that clients cannot add those things.  Therefore
> it has roughly the same degree of additional meaning over `public` as
> `open` does.
>
>
> The difference I see is precisely that 'public' and 'open' modifiers limit
> what the client of a module can do while closed limits what future versions
> of a module can do. Feels quite different to me.
>
>
> This is a reasonable point and is perhaps the strongest argument made
> against my proposal thus far.  However, I think we have to consider my
> proposal relative to the alternatives.
>
> The only alternative I am aware of is making `public enum` the resilient
> variety and using `@closed public enum` for the closed variety.  This means
> that `public` will have at least two different semantics (three if we don’t
> reconcile classes and protocols).  It also means that the resilient variety
> is effectively the default.  I am really happy that we decide not to have a
> default between `open` and `public` and think the best choice is that we
> don’t have one here either.  The fact that we have a way to do this while
> solving the inconsistent semantics of `public` feels like a net win to me.
>
>
>
> First of all, the Library Evolution document you linked says toward at the
> top that "this document is primarily concerned with binary compatibility,
> i.e. what changes can safely be made to a library between releases that
> will not break memory-safety or type-safety, or cause clients to fail to
> run at all." It seems to me that the @closed introduced in that document is
> much more about library resilience than about only closing down the
> addition of new cases: that's why it also talks about reordering and all
> other changes that can change the memory layout.
>
> Swift 3 having introduced both fileprivate and open has complexified the
> access level story for developers and library authors. That complexity is
> the cost that we have paid for more expressiveness. But if we continue
> adding new access control modifiers to express new semantics, we may be
> going too far: perfect is the enemy of good.
>
>
> Both of those arguments explain why I think closed should be introduced,
> but only as a rarely-used attribute for library authors which need to
> express ABI resilience, and not as an extra access modifier.
>
>
> `closed` is about much more than binary compatibility.  Any time a library
> publishes an enum that clients can reasonably be expected to switch
> statements over the library should strive to make it `closed` wherever
> possible.  Otherwise clients are expected to handle unknown future cases by
> design.  That is a design smell if you ask me.  This means that we can
> expect libraries to often carefully design such enums in a way that allows
> them to be `closed`.  The use case for resilient enums is in things like
> mutually exclusive option sets received as input to the module and for
> which it would be unusual for clients of the library to write a switch
> statement over.
>
> With this in mind, `closed` should not be a rarely-used attribute at all.
> In fact it will often be the best choice.  This is a big motivation behind
> my desire to see it on equal footing with `public` and `open`.
>
> In regards to the complexity of the access model - if you look closely,
> `public` has three subtly different meanings today.  That kind of
> inconsistency is part of the complexity of it.  And as noted, `closed` is a
> concept that *will* play a significant role in Swift, regardless of how we
> spell it.  What my proposal aims to do is to incorporate it into a
> consistent system of outside-the-module access modifiers.
>
> One can make a very reasonable argument that access modifiers should
> *only* be in the business of talking about visibility 

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-12 Thread Matthew Johnson via swift-evolution

> On Feb 12, 2017, at 10:24 AM, David Hart  wrote:
> 
> 
> On 12 Feb 2017, at 16:38, Matthew Johnson  > wrote:
> 
>> 
>>> On Feb 12, 2017, at 12:50 AM, David Hart >> > wrote:
>>> 
>>> Hi Matthew,
>>> 
>>> I've read your proposal ideas and most of the discussions on the thread, 
>>> and I'd like to provide some personal feedback.
>>> 
>>> Swift already has a complicated "access modifier" story so I think we 
>>> really want a good reason to introduce a new one. And the problem I see is 
>>> that `closed` has much less semantic weight than the other modifiers.
>> 
>> How so?  I’m not sure if I catch your meaning here.  It feels to me like it 
>> has the same semantic weight as `open`: prohibiting future versions of a 
>> module from adding cases / subclasses / conformances is roughly the inverse 
>> of lifting the restriction that clients cannot add those things.  Therefore 
>> it has roughly the same degree of additional meaning over `public` as `open` 
>> does.
> 
> The difference I see is precisely that 'public' and 'open' modifiers limit 
> what the client of a module can do while closed limits what future versions 
> of a module can do. Feels quite different to me.

This is a reasonable point and is perhaps the strongest argument made against 
my proposal thus far.  However, I think we have to consider my proposal 
relative to the alternatives.  

The only alternative I am aware of is making `public enum` the resilient 
variety and using `@closed public enum` for the closed variety.  This means 
that `public` will have at least two different semantics (three if we don’t 
reconcile classes and protocols).  It also means that the resilient variety is 
effectively the default.  I am really happy that we decide not to have a 
default between `open` and `public` and think the best choice is that we don’t 
have one here either.  The fact that we have a way to do this while solving the 
inconsistent semantics of `public` feels like a net win to me.

> 
>>> 
>>> First of all, the Library Evolution document you linked says toward at the 
>>> top that "this document is primarily concerned with binary compatibility, 
>>> i.e. what changes can safely be made to a library between releases that 
>>> will not break memory-safety or type-safety, or cause clients to fail to 
>>> run at all." It seems to me that the @closed introduced in that document is 
>>> much more about library resilience than about only closing down the 
>>> addition of new cases: that's why it also talks about reordering and all 
>>> other changes that can change the memory layout.
>>> 
>>> Swift 3 having introduced both fileprivate and open has complexified the 
>>> access level story for developers and library authors. That complexity is 
>>> the cost that we have paid for more expressiveness. But if we continue 
>>> adding new access control modifiers to express new semantics, we may be 
>>> going too far: perfect is the enemy of good.
>>> 
>>> Both of those arguments explain why I think closed should be introduced, 
>>> but only as a rarely-used attribute for library authors which need to 
>>> express ABI resilience, and not as an extra access modifier.
>> 
>> `closed` is about much more than binary compatibility.  Any time a library 
>> publishes an enum that clients can reasonably be expected to switch 
>> statements over the library should strive to make it `closed` wherever 
>> possible.  Otherwise clients are expected to handle unknown future cases by 
>> design.  That is a design smell if you ask me.  This means that we can 
>> expect libraries to often carefully design such enums in a way that allows 
>> them to be `closed`.  The use case for resilient enums is in things like 
>> mutually exclusive option sets received as input to the module and for which 
>> it would be unusual for clients of the library to write a switch statement 
>> over.
>> 
>> With this in mind, `closed` should not be a rarely-used attribute at all.  
>> In fact it will often be the best choice.  This is a big motivation behind 
>> my desire to see it on equal footing with `public` and `open`.
>> 
>> In regards to the complexity of the access model - if you look closely, 
>> `public` has three subtly different meanings today.  That kind of 
>> inconsistency is part of the complexity of it.  And as noted, `closed` is a 
>> concept that *will* play a significant role in Swift, regardless of how we 
>> spell it.  What my proposal aims to do is to incorporate it into a 
>> consistent system of outside-the-module access modifiers.  
>> 
>> One can make a very reasonable argument that access modifiers should *only* 
>> be in the business of talking about visibility and should stay out of the 
>> business of talking about “who can add to the set of cases / subclasses / 
>> conformances”.  The time for that argument was when we had the `open` 
>> 

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-12 Thread David Hart via swift-evolution

> On 12 Feb 2017, at 16:38, Matthew Johnson  wrote:
> 
> 
>> On Feb 12, 2017, at 12:50 AM, David Hart  wrote:
>> 
>> Hi Matthew,
>> 
>> I've read your proposal ideas and most of the discussions on the thread, and 
>> I'd like to provide some personal feedback.
>> 
>> Swift already has a complicated "access modifier" story so I think we really 
>> want a good reason to introduce a new one. And the problem I see is that 
>> `closed` has much less semantic weight than the other modifiers.
> 
> How so?  I’m not sure if I catch your meaning here.  It feels to me like it 
> has the same semantic weight as `open`: prohibiting future versions of a 
> module from adding cases / subclasses / conformances is roughly the inverse 
> of lifting the restriction that clients cannot add those things.  Therefore 
> it has roughly the same degree of additional meaning over `public` as `open` 
> does.

The difference I see is precisely that 'public' and 'open' modifiers limit what 
the client of a module can do while closed limits what future versions of a 
module can do. Feels quite different to me.

>> 
>> First of all, the Library Evolution document you linked says toward at the 
>> top that "this document is primarily concerned with binary compatibility, 
>> i.e. what changes can safely be made to a library between releases that will 
>> not break memory-safety or type-safety, or cause clients to fail to run at 
>> all." It seems to me that the @closed introduced in that document is much 
>> more about library resilience than about only closing down the addition of 
>> new cases: that's why it also talks about reordering and all other changes 
>> that can change the memory layout.
>> 
>> Swift 3 having introduced both fileprivate and open has complexified the 
>> access level story for developers and library authors. That complexity is 
>> the cost that we have paid for more expressiveness. But if we continue 
>> adding new access control modifiers to express new semantics, we may be 
>> going too far: perfect is the enemy of good.
>> 
>> Both of those arguments explain why I think closed should be introduced, but 
>> only as a rarely-used attribute for library authors which need to express 
>> ABI resilience, and not as an extra access modifier.
> 
> `closed` is about much more than binary compatibility.  Any time a library 
> publishes an enum that clients can reasonably be expected to switch 
> statements over the library should strive to make it `closed` wherever 
> possible.  Otherwise clients are expected to handle unknown future cases by 
> design.  That is a design smell if you ask me.  This means that we can expect 
> libraries to often carefully design such enums in a way that allows them to 
> be `closed`.  The use case for resilient enums is in things like mutually 
> exclusive option sets received as input to the module and for which it would 
> be unusual for clients of the library to write a switch statement over.
> 
> With this in mind, `closed` should not be a rarely-used attribute at all.  In 
> fact it will often be the best choice.  This is a big motivation behind my 
> desire to see it on equal footing with `public` and `open`.
> 
> In regards to the complexity of the access model - if you look closely, 
> `public` has three subtly different meanings today.  That kind of 
> inconsistency is part of the complexity of it.  And as noted, `closed` is a 
> concept that *will* play a significant role in Swift, regardless of how we 
> spell it.  What my proposal aims to do is to incorporate it into a consistent 
> system of outside-the-module access modifiers.  
> 
> One can make a very reasonable argument that access modifiers should *only* 
> be in the business of talking about visibility and should stay out of the 
> business of talking about “who can add to the set of cases / subclasses / 
> conformances”.  The time for that argument was when we had the `open` 
> discussion last year.  I happen to like the direction we went because it 
> places `public` and `open` on equal footing.  And now that we *have* decided 
> to go in this direction, I think we should stick with it when we introduce 
> `closed`.
> 
>>  
>> David
>> 
>>> On 9 Feb 2017, at 00:05, Matthew Johnson via swift-evolution 
>>>  wrote:
>>> 
>>> I’ve been thinking a lot about our public access modifier story lately in 
>>> the context of both protocols and enums.  I believe we should move further 
>>> in the direction we took when introducing the `open` keyword.  I have 
>>> identified what I think is a promising direction and am interested in 
>>> feedback from the community.  If community feedback is positive I will 
>>> flesh this out into a more complete proposal draft.
>>> 
>>> 
>>> Background and Motivation:
>>> 
>>> In Swift 3 we had an extended debate regarding whether or not to allow 
>>> inheritance of public classes by default or to require an annotation for 

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-12 Thread Matthew Johnson via swift-evolution

> On Feb 12, 2017, at 12:50 AM, David Hart  wrote:
> 
> Hi Matthew,
> 
> I've read your proposal ideas and most of the discussions on the thread, and 
> I'd like to provide some personal feedback.
> 
> Swift already has a complicated "access modifier" story so I think we really 
> want a good reason to introduce a new one. And the problem I see is that 
> `closed` has much less semantic weight than the other modifiers.

How so?  I’m not sure if I catch your meaning here.  It feels to me like it has 
the same semantic weight as `open`: prohibiting future versions of a module 
from adding cases / subclasses / conformances is roughly the inverse of lifting 
the restriction that clients cannot add those things.  Therefore it has roughly 
the same degree of additional meaning over `public` as `open` does.

> 
> First of all, the Library Evolution document you linked says toward at the 
> top that "this document is primarily concerned with binary compatibility, 
> i.e. what changes can safely be made to a library between releases that will 
> not break memory-safety or type-safety, or cause clients to fail to run at 
> all." It seems to me that the @closed introduced in that document is much 
> more about library resilience than about only closing down the addition of 
> new cases: that's why it also talks about reordering and all other changes 
> that can change the memory layout.
> 
> Swift 3 having introduced both fileprivate and open has complexified the 
> access level story for developers and library authors. That complexity is the 
> cost that we have paid for more expressiveness. But if we continue adding new 
> access control modifiers to express new semantics, we may be going too far: 
> perfect is the enemy of good.
> 
> Both of those arguments explain why I think closed should be introduced, but 
> only as a rarely-used attribute for library authors which need to express ABI 
> resilience, and not as an extra access modifier.

`closed` is about much more than binary compatibility.  Any time a library 
publishes an enum that clients can reasonably be expected to switch statements 
over the library should strive to make it `closed` wherever possible.  
Otherwise clients are expected to handle unknown future cases by design.  That 
is a design smell if you ask me.  This means that we can expect libraries to 
often carefully design such enums in a way that allows them to be `closed`.  
The use case for resilient enums is in things like mutually exclusive option 
sets received as input to the module and for which it would be unusual for 
clients of the library to write a switch statement over.

With this in mind, `closed` should not be a rarely-used attribute at all.  In 
fact it will often be the best choice.  This is a big motivation behind my 
desire to see it on equal footing with `public` and `open`.

In regards to the complexity of the access model - if you look closely, 
`public` has three subtly different meanings today.  That kind of inconsistency 
is part of the complexity of it.  And as noted, `closed` is a concept that 
*will* play a significant role in Swift, regardless of how we spell it.  What 
my proposal aims to do is to incorporate it into a consistent system of 
outside-the-module access modifiers.  

One can make a very reasonable argument that access modifiers should *only* be 
in the business of talking about visibility and should stay out of the business 
of talking about “who can add to the set of cases / subclasses / conformances”. 
 The time for that argument was when we had the `open` discussion last year.  I 
happen to like the direction we went because it places `public` and `open` on 
equal footing.  And now that we *have* decided to go in this direction, I think 
we should stick with it when we introduce `closed`.

>  
> David
> 
> On 9 Feb 2017, at 00:05, Matthew Johnson via swift-evolution 
> > wrote:
> 
>> I’ve been thinking a lot about our public access modifier story lately in 
>> the context of both protocols and enums.  I believe we should move further 
>> in the direction we took when introducing the `open` keyword.  I have 
>> identified what I think is a promising direction and am interested in 
>> feedback from the community.  If community feedback is positive I will flesh 
>> this out into a more complete proposal draft.
>> 
>> 
>> Background and Motivation:
>> 
>> In Swift 3 we had an extended debate regarding whether or not to allow 
>> inheritance of public classes by default or to require an annotation for 
>> classes that could be subclassed outside the module.  The decision we 
>> reached was to avoid having a default at all, and instead make `open` an 
>> access modifier.  The result is library authors are required to consider the 
>> behavior they wish for each class.  Both behaviors are equally convenient 
>> (neither is penalized by requiring an additional boilerplate-y 

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-12 Thread Matthew Johnson via swift-evolution

> On Feb 11, 2017, at 4:41 PM, Karl Wagner  wrote:
> 
> 
>> On 11 Feb 2017, at 20:50, Matthew Johnson via swift-evolution 
>> > wrote:
>> 
>>> 
>>> On Feb 11, 2017, at 12:40 PM, Xiaodi Wu >> > wrote:
>>> 
>>> On Sat, Feb 11, 2017 at 6:41 AM, Matthew Johnson >> > wrote:
>>> 
>>> 
>>> Sent from my iPad
>>> 
>>> On Feb 10, 2017, at 9:48 PM, Xiaodi Wu >> > wrote:
>>> 
 On Wed, Feb 8, 2017 at 5:05 PM, Matthew Johnson via swift-evolution 
 > wrote:
 I’ve been thinking a lot about our public access modifier story lately in 
 the context of both protocols and enums.  I believe we should move further 
 in the direction we took when introducing the `open` keyword.  I have 
 identified what I think is a promising direction and am interested in 
 feedback from the community.  If community feedback is positive I will 
 flesh this out into a more complete proposal draft.
 
 
 Background and Motivation:
 
 In Swift 3 we had an extended debate regarding whether or not to allow 
 inheritance of public classes by default or to require an annotation for 
 classes that could be subclassed outside the module.  The decision we 
 reached was to avoid having a default at all, and instead make `open` an 
 access modifier.  The result is library authors are required to consider 
 the behavior they wish for each class.  Both behaviors are equally 
 convenient (neither is penalized by requiring an additional boilerplate-y 
 annotation).
 
 A recent thread 
 (https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170206/031566.html
  
 )
  discussed a similar tradeoff regarding whether public enums should commit 
 to a fixed set of cases by default or not.  The current behavior is that 
 they *do* commit to a fixed set of cases and there is no option (afaik) to 
 modify that behavior.  The Library Evolution document 
 (https://github.com/apple/swift/blob/master/docs/LibraryEvolution.rst#enums
  
 )
  suggests a desire to change this before locking down ABI such that public 
 enums *do not* make this commitment by default, and are required to opt-in 
 to this behavior using an `@closed` annotation.
 
 In the previous discussion I stated a strong preference that closed enums 
 *not* be penalized with an additional annotation.  This is because I feel 
 pretty strongly that it is a design smell to: 1) expose cases publicly if 
 consumers of the API are not expected to switch on them and 2) require 
 users to handle unknown future cases if they are likely to switch over the 
 cases in correct use of the API.
 
 The conclusion I came to in that thread is that we should adopt the same 
 strategy as we did with classes: there should not be a default.
 
 There have also been several discussions both on the list and via Twitter 
 regarding whether or not we should allow closed protocols.  In a recent 
 Twitter discussion Joe Groff suggested that we don’t need them because we 
 should use an enum when there is a fixed set of conforming types.  There 
 are at least two  reasons why I still think we *should* add support for 
 closed protocols.
 
 As noted above (and in the previous thread in more detail), if the set of 
 types (cases) isn’t intended to be fixed (i.e. the library may add new 
 types in the future) an enum is likely not a good choice.  Using a closed 
 protocol discourages the user from switching and prevents the user from 
 adding conformances that are not desired.
 
 Another use case supported by closed protocols is a design where users are 
 not allowed to conform directly to a protocol, but instead are required to 
 conform to one of several protocols which refine the closed protocol.  
 Enums are not a substitute for this use case.  The only option is to 
 resort to documentation and runtime checks.
 
 
 Proposal:
 
 This proposal introduces the new access modifier `closed` as well as 
 clarifying the meaning of `public` and expanding the use of `open`.  This 
 provides consistent capabilities and semantics across enums, classes and 
 protocols.
 
 `open` is the most permissive modifier.  The symbol is visible outside the 
 module and both users and future versions of the library are allowed to 
 add new cases, subclasses or conformances.  (Note: this proposal does 

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-12 Thread Slava Pestov via swift-evolution

> On Feb 11, 2017, at 2:41 PM, Karl Wagner via swift-evolution 
>  wrote:

> For example, the compiler squashes the layout of an enum in to the smallest 
> type which can represent all of its cases - so if you only have 2 cases, your 
> enum will be an Int1 (possibly stored in a way which overlaps the payload, if 
> there are spare bits to do so).

This is still the case with resilient enums. The current implementation of 
resilient value types does not change the memory layout of those types. Rather, 
it makes clients access the values indirectly, using a value witness table 
instead of making assumptions about the size, etc.

> 
> If we introduce some kind of forwards-compatible enum, it should explicitly 
> be something different (like an “open” enum). It’s the nichest of 
> niche-cases, would change the layout and prohibit optimisations, and make 
> those objects more difficult to reason about.

Perhaps, but note that resilience does *not* prohibit layout optimizations — 
instead, it means that clients use an indirect access pattern where knowledge 
of the layout is encapsulated in the library.

Slava

> 
>> 
>>>  
 3. In Swift 5, upgrade the warning to an error for non-exhaustiveness if a 
 switch statement over a public enum doesn't have a `default` statement. 
 Now, new syntax to extend an `open enum` can be introduced and the 
 compiler can treat closed and public enums differently.
>>> 
>>> If the community and core team support this strategy I will also.  It seems 
>>> reasonable and speeds up the transition by using the point release.  That's 
>>> a great idea!
>>> 
>> 
>> ___
>> 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


Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-12 Thread Adrian Zubarev via swift-evolution
Hi Brent, I understand that SubC.cc as C does not work, that’s the case in my 
bikeshedding example I noticed that because the enum case is always known at 
compile time, there will be an error with informs you to downgrade SubC to one 
of its super-types case. Plus I forget about the RawRepresentable for enums 
while making this example completely - my bad.

I might not fully understand how sub-typing on value types should work, that’s 
way I’m looking forward to the document Matthew will write one day. :)

Sub-typing enums to remove cases sounds also really interesting to me. :)

Thank you for your feedback.



-- 
Adrian Zubarev
Sent with Airmail

Am 12. Februar 2017 um 09:57:39, Brent Royal-Gordon (br...@architechies.com) 
schrieb:

> On Feb 11, 2017, at 2:25 AM, Adrian Zubarev via swift-evolution 
>  wrote:  
>  
> // Allowed because `C` is open, and open allows sub-typing, conforming  
> // and overriding to the client  
> enum SubC : C {  
> case cc  
> }  

There's a subtle mistake here. For a sum type, subtyping actually means 
*removing* cases, not *adding* cases. (Or it can mean changing some of the 
associated types into their subtypes, but that's a different story.)  

To understand why, think about casting between `C` and `SubC`. Specifically, 
imagine this upcast:  

SubC.cc as C  

What is this supposed to do? There is no `cc` case in `C`, so `SubC.cc` cannot 
be represented as a `C`. That means `SubC` is not a subtype of `C`. In fact, 
`SubC` would be a *supertype* of `C`—you would need to say `SubC.cc as? C`, but 
you could always say `C.c as SubC`.  

(The ultimate expression of this is that `Never`—which can be thought of as the 
subtype of all types—is an empty enum.)  

That's not to say that this is a feature we should add; rather, it's to say 
that the concept of inheritance doesn't really make any sense for `enum`s.  

Just something I noticed when I was reading this thread. I'll have more to say 
on the main topic, hopefully soon.  

--  
Brent Royal-Gordon  
Architechies  

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


Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-12 Thread Brent Royal-Gordon via swift-evolution
> On Feb 11, 2017, at 2:25 AM, Adrian Zubarev via swift-evolution 
>  wrote:
> 
> // Allowed because `C` is open, and open allows sub-typing, conforming  
> // and overriding to the client
> enum SubC : C {
> case cc
> }

There's a subtle mistake here. For a sum type, subtyping actually means 
*removing* cases, not *adding* cases. (Or it can mean changing some of the 
associated types into their subtypes, but that's a different story.)

To understand why, think about casting between `C` and `SubC`. Specifically, 
imagine this upcast:

SubC.cc as C

What is this supposed to do? There is no `cc` case in `C`, so `SubC.cc` cannot 
be represented as a `C`. That means `SubC` is not a subtype of `C`. In fact, 
`SubC` would be a *supertype* of `C`—you would need to say `SubC.cc as? C`, but 
you could always say `C.c as SubC`.

(The ultimate expression of this is that `Never`—which can be thought of as the 
subtype of all types—is an empty enum.)

That's not to say that this is a feature we should add; rather, it's to say 
that the concept of inheritance doesn't really make any sense for `enum`s. 

Just something I noticed when I was reading this thread. I'll have more to say 
on the main topic, hopefully soon.

-- 
Brent Royal-Gordon
Architechies

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


Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-11 Thread David Hart via swift-evolution
Hi Matthew,

I've read your proposal ideas and most of the discussions on the thread, and 
I'd like to provide some personal feedback.

Swift already has a complicated "access modifier" story so I think we really 
want a good reason to introduce a new one. And the problem I see is that 
`closed` has much less semantic weight than the other modifiers.

First of all, the Library Evolution document you linked says toward at the top 
that "this document is primarily concerned with binary compatibility, i.e. what 
changes can safely be made to a library between releases that will not break 
memory-safety or type-safety, or cause clients to fail to run at all." It seems 
to me that the @closed introduced in that document is much more about library 
resilience than about only closing down the addition of new cases: that's why 
it also talks about reordering and all other changes that can change the memory 
layout.

Swift 3 having introduced both fileprivate and open has complexified the access 
level story for developers and library authors. That complexity is the cost 
that we have paid for more expressiveness. But if we continue adding new access 
control modifiers to express new semantics, we may be going too far: perfect is 
the enemy of good.

Both of those arguments explain why I think closed should be introduced, but 
only as a rarely-used attribute for library authors which need to express ABI 
resilience, and not as an extra access modifier.

David

> On 9 Feb 2017, at 00:05, Matthew Johnson via swift-evolution 
>  wrote:
> 
> I’ve been thinking a lot about our public access modifier story lately in the 
> context of both protocols and enums.  I believe we should move further in the 
> direction we took when introducing the `open` keyword.  I have identified 
> what I think is a promising direction and am interested in feedback from the 
> community.  If community feedback is positive I will flesh this out into a 
> more complete proposal draft.
> 
> 
> Background and Motivation:
> 
> In Swift 3 we had an extended debate regarding whether or not to allow 
> inheritance of public classes by default or to require an annotation for 
> classes that could be subclassed outside the module.  The decision we reached 
> was to avoid having a default at all, and instead make `open` an access 
> modifier.  The result is library authors are required to consider the 
> behavior they wish for each class.  Both behaviors are equally convenient 
> (neither is penalized by requiring an additional boilerplate-y annotation).
> 
> A recent thread 
> (https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170206/031566.html)
>  discussed a similar tradeoff regarding whether public enums should commit to 
> a fixed set of cases by default or not.  The current behavior is that they 
> *do* commit to a fixed set of cases and there is no option (afaik) to modify 
> that behavior.  The Library Evolution document 
> (https://github.com/apple/swift/blob/master/docs/LibraryEvolution.rst#enums) 
> suggests a desire to change this before locking down ABI such that public 
> enums *do not* make this commitment by default, and are required to opt-in to 
> this behavior using an `@closed` annotation.
> 
> In the previous discussion I stated a strong preference that closed enums 
> *not* be penalized with an additional annotation.  This is because I feel 
> pretty strongly that it is a design smell to: 1) expose cases publicly if 
> consumers of the API are not expected to switch on them and 2) require users 
> to handle unknown future cases if they are likely to switch over the cases in 
> correct use of the API.
> 
> The conclusion I came to in that thread is that we should adopt the same 
> strategy as we did with classes: there should not be a default.
> 
> There have also been several discussions both on the list and via Twitter 
> regarding whether or not we should allow closed protocols.  In a recent 
> Twitter discussion Joe Groff suggested that we don’t need them because we 
> should use an enum when there is a fixed set of conforming types.  There are 
> at least two  reasons why I still think we *should* add support for closed 
> protocols.
> 
> As noted above (and in the previous thread in more detail), if the set of 
> types (cases) isn’t intended to be fixed (i.e. the library may add new types 
> in the future) an enum is likely not a good choice.  Using a closed protocol 
> discourages the user from switching and prevents the user from adding 
> conformances that are not desired.
> 
> Another use case supported by closed protocols is a design where users are 
> not allowed to conform directly to a protocol, but instead are required to 
> conform to one of several protocols which refine the closed protocol.  Enums 
> are not a substitute for this use case.  The only option is to resort to 
> documentation and runtime checks.
> 
> 
> Proposal:
> 
> This proposal introduces the new access 

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-11 Thread Karl Wagner via swift-evolution

> On 11 Feb 2017, at 20:50, Matthew Johnson via swift-evolution 
>  wrote:
> 
>> 
>> On Feb 11, 2017, at 12:40 PM, Xiaodi Wu > > wrote:
>> 
>> On Sat, Feb 11, 2017 at 6:41 AM, Matthew Johnson > > wrote:
>> 
>> 
>> Sent from my iPad
>> 
>> On Feb 10, 2017, at 9:48 PM, Xiaodi Wu > > wrote:
>> 
>>> On Wed, Feb 8, 2017 at 5:05 PM, Matthew Johnson via swift-evolution 
>>> > wrote:
>>> I’ve been thinking a lot about our public access modifier story lately in 
>>> the context of both protocols and enums.  I believe we should move further 
>>> in the direction we took when introducing the `open` keyword.  I have 
>>> identified what I think is a promising direction and am interested in 
>>> feedback from the community.  If community feedback is positive I will 
>>> flesh this out into a more complete proposal draft.
>>> 
>>> 
>>> Background and Motivation:
>>> 
>>> In Swift 3 we had an extended debate regarding whether or not to allow 
>>> inheritance of public classes by default or to require an annotation for 
>>> classes that could be subclassed outside the module.  The decision we 
>>> reached was to avoid having a default at all, and instead make `open` an 
>>> access modifier.  The result is library authors are required to consider 
>>> the behavior they wish for each class.  Both behaviors are equally 
>>> convenient (neither is penalized by requiring an additional boilerplate-y 
>>> annotation).
>>> 
>>> A recent thread 
>>> (https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170206/031566.html
>>>  
>>> )
>>>  discussed a similar tradeoff regarding whether public enums should commit 
>>> to a fixed set of cases by default or not.  The current behavior is that 
>>> they *do* commit to a fixed set of cases and there is no option (afaik) to 
>>> modify that behavior.  The Library Evolution document 
>>> (https://github.com/apple/swift/blob/master/docs/LibraryEvolution.rst#enums 
>>> )
>>>  suggests a desire to change this before locking down ABI such that public 
>>> enums *do not* make this commitment by default, and are required to opt-in 
>>> to this behavior using an `@closed` annotation.
>>> 
>>> In the previous discussion I stated a strong preference that closed enums 
>>> *not* be penalized with an additional annotation.  This is because I feel 
>>> pretty strongly that it is a design smell to: 1) expose cases publicly if 
>>> consumers of the API are not expected to switch on them and 2) require 
>>> users to handle unknown future cases if they are likely to switch over the 
>>> cases in correct use of the API.
>>> 
>>> The conclusion I came to in that thread is that we should adopt the same 
>>> strategy as we did with classes: there should not be a default.
>>> 
>>> There have also been several discussions both on the list and via Twitter 
>>> regarding whether or not we should allow closed protocols.  In a recent 
>>> Twitter discussion Joe Groff suggested that we don’t need them because we 
>>> should use an enum when there is a fixed set of conforming types.  There 
>>> are at least two  reasons why I still think we *should* add support for 
>>> closed protocols.
>>> 
>>> As noted above (and in the previous thread in more detail), if the set of 
>>> types (cases) isn’t intended to be fixed (i.e. the library may add new 
>>> types in the future) an enum is likely not a good choice.  Using a closed 
>>> protocol discourages the user from switching and prevents the user from 
>>> adding conformances that are not desired.
>>> 
>>> Another use case supported by closed protocols is a design where users are 
>>> not allowed to conform directly to a protocol, but instead are required to 
>>> conform to one of several protocols which refine the closed protocol.  
>>> Enums are not a substitute for this use case.  The only option is to resort 
>>> to documentation and runtime checks.
>>> 
>>> 
>>> Proposal:
>>> 
>>> This proposal introduces the new access modifier `closed` as well as 
>>> clarifying the meaning of `public` and expanding the use of `open`.  This 
>>> provides consistent capabilities and semantics across enums, classes and 
>>> protocols.
>>> 
>>> `open` is the most permissive modifier.  The symbol is visible outside the 
>>> module and both users and future versions of the library are allowed to add 
>>> new cases, subclasses or conformances.  (Note: this proposal does not 
>>> introduce user-extensible `open` enums, but provides the syntax that would 
>>> be used if they are added to the language)
>>> 
>>> `public` makes the symbol visible without allowing the user to add 

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-11 Thread Xiaodi Wu via swift-evolution
On Sat, Feb 11, 2017 at 1:50 PM, Matthew Johnson 
wrote:

>
> On Feb 11, 2017, at 12:40 PM, Xiaodi Wu  wrote:
>
> On Sat, Feb 11, 2017 at 6:41 AM, Matthew Johnson 
> wrote:
>
>>
>>
>> Sent from my iPad
>>
>> On Feb 10, 2017, at 9:48 PM, Xiaodi Wu  wrote:
>>
>> On Wed, Feb 8, 2017 at 5:05 PM, Matthew Johnson via swift-evolution <
>> swift-evolution@swift.org> wrote:
>>
>>> I’ve been thinking a lot about our public access modifier story lately
>>> in the context of both protocols and enums.  I believe we should move
>>> further in the direction we took when introducing the `open` keyword.  I
>>> have identified what I think is a promising direction and am interested in
>>> feedback from the community.  If community feedback is positive I will
>>> flesh this out into a more complete proposal draft.
>>>
>>>
>>> Background and Motivation:
>>>
>>> In Swift 3 we had an extended debate regarding whether or not to allow
>>> inheritance of public classes by default or to require an annotation for
>>> classes that could be subclassed outside the module.  The decision we
>>> reached was to avoid having a default at all, and instead make `open` an
>>> access modifier.  The result is library authors are required to consider
>>> the behavior they wish for each class.  Both behaviors are equally
>>> convenient (neither is penalized by requiring an additional boilerplate-y
>>> annotation).
>>>
>>> A recent thread (https://lists.swift.org/piper
>>> mail/swift-evolution/Week-of-Mon-20170206/031566.html) discussed a
>>> similar tradeoff regarding whether public enums should commit to a fixed
>>> set of cases by default or not.  The current behavior is that they *do*
>>> commit to a fixed set of cases and there is no option (afaik) to modify
>>> that behavior.  The Library Evolution document (
>>> https://github.com/apple/swift/blob/master/docs/LibraryEvol
>>> ution.rst#enums) suggests a desire to change this before locking down
>>> ABI such that public enums *do not* make this commitment by default, and
>>> are required to opt-in to this behavior using an `@closed` annotation.
>>>
>>> In the previous discussion I stated a strong preference that closed
>>> enums *not* be penalized with an additional annotation.  This is because I
>>> feel pretty strongly that it is a design smell to: 1) expose cases publicly
>>> if consumers of the API are not expected to switch on them and 2) require
>>> users to handle unknown future cases if they are likely to switch over the
>>> cases in correct use of the API.
>>>
>>> The conclusion I came to in that thread is that we should adopt the same
>>> strategy as we did with classes: there should not be a default.
>>>
>>> There have also been several discussions both on the list and via
>>> Twitter regarding whether or not we should allow closed protocols.  In a
>>> recent Twitter discussion Joe Groff suggested that we don’t need them
>>> because we should use an enum when there is a fixed set of conforming
>>> types.  There are at least two  reasons why I still think we *should* add
>>> support for closed protocols.
>>>
>>> As noted above (and in the previous thread in more detail), if the set
>>> of types (cases) isn’t intended to be fixed (i.e. the library may add new
>>> types in the future) an enum is likely not a good choice.  Using a closed
>>> protocol discourages the user from switching and prevents the user from
>>> adding conformances that are not desired.
>>>
>>> Another use case supported by closed protocols is a design where users
>>> are not allowed to conform directly to a protocol, but instead are required
>>> to conform to one of several protocols which refine the closed protocol.
>>> Enums are not a substitute for this use case.  The only option is to resort
>>> to documentation and runtime checks.
>>>
>>>
>>> Proposal:
>>>
>>> This proposal introduces the new access modifier `closed` as well as
>>> clarifying the meaning of `public` and expanding the use of `open`.  This
>>> provides consistent capabilities and semantics across enums, classes and
>>> protocols.
>>>
>>> `open` is the most permissive modifier.  The symbol is visible outside
>>> the module and both users and future versions of the library are allowed to
>>> add new cases, subclasses or conformances.  (Note: this proposal does not
>>> introduce user-extensible `open` enums, but provides the syntax that would
>>> be used if they are added to the language)
>>>
>>> `public` makes the symbol visible without allowing the user to add new
>>> cases, subclasses or conformances.  The library reserves the right to add
>>> new cases, subclasses or conformances in a future version.
>>>
>>> `closed` is the most restrictive modifier.  The symbol is visible
>>> publicly with the commitment that future versions of the library are *also*
>>> prohibited from adding new cases, subclasses or conformances.
>>> Additionally, all cases, subclasses 

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-11 Thread Matthew Johnson via swift-evolution

> On Feb 11, 2017, at 12:40 PM, Xiaodi Wu  wrote:
> 
> On Sat, Feb 11, 2017 at 6:41 AM, Matthew Johnson  > wrote:
> 
> 
> Sent from my iPad
> 
> On Feb 10, 2017, at 9:48 PM, Xiaodi Wu  > wrote:
> 
>> On Wed, Feb 8, 2017 at 5:05 PM, Matthew Johnson via swift-evolution 
>> > wrote:
>> I’ve been thinking a lot about our public access modifier story lately in 
>> the context of both protocols and enums.  I believe we should move further 
>> in the direction we took when introducing the `open` keyword.  I have 
>> identified what I think is a promising direction and am interested in 
>> feedback from the community.  If community feedback is positive I will flesh 
>> this out into a more complete proposal draft.
>> 
>> 
>> Background and Motivation:
>> 
>> In Swift 3 we had an extended debate regarding whether or not to allow 
>> inheritance of public classes by default or to require an annotation for 
>> classes that could be subclassed outside the module.  The decision we 
>> reached was to avoid having a default at all, and instead make `open` an 
>> access modifier.  The result is library authors are required to consider the 
>> behavior they wish for each class.  Both behaviors are equally convenient 
>> (neither is penalized by requiring an additional boilerplate-y annotation).
>> 
>> A recent thread 
>> (https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170206/031566.html
>>  
>> )
>>  discussed a similar tradeoff regarding whether public enums should commit 
>> to a fixed set of cases by default or not.  The current behavior is that 
>> they *do* commit to a fixed set of cases and there is no option (afaik) to 
>> modify that behavior.  The Library Evolution document 
>> (https://github.com/apple/swift/blob/master/docs/LibraryEvolution.rst#enums 
>> )
>>  suggests a desire to change this before locking down ABI such that public 
>> enums *do not* make this commitment by default, and are required to opt-in 
>> to this behavior using an `@closed` annotation.
>> 
>> In the previous discussion I stated a strong preference that closed enums 
>> *not* be penalized with an additional annotation.  This is because I feel 
>> pretty strongly that it is a design smell to: 1) expose cases publicly if 
>> consumers of the API are not expected to switch on them and 2) require users 
>> to handle unknown future cases if they are likely to switch over the cases 
>> in correct use of the API.
>> 
>> The conclusion I came to in that thread is that we should adopt the same 
>> strategy as we did with classes: there should not be a default.
>> 
>> There have also been several discussions both on the list and via Twitter 
>> regarding whether or not we should allow closed protocols.  In a recent 
>> Twitter discussion Joe Groff suggested that we don’t need them because we 
>> should use an enum when there is a fixed set of conforming types.  There are 
>> at least two  reasons why I still think we *should* add support for closed 
>> protocols.
>> 
>> As noted above (and in the previous thread in more detail), if the set of 
>> types (cases) isn’t intended to be fixed (i.e. the library may add new types 
>> in the future) an enum is likely not a good choice.  Using a closed protocol 
>> discourages the user from switching and prevents the user from adding 
>> conformances that are not desired.
>> 
>> Another use case supported by closed protocols is a design where users are 
>> not allowed to conform directly to a protocol, but instead are required to 
>> conform to one of several protocols which refine the closed protocol.  Enums 
>> are not a substitute for this use case.  The only option is to resort to 
>> documentation and runtime checks.
>> 
>> 
>> Proposal:
>> 
>> This proposal introduces the new access modifier `closed` as well as 
>> clarifying the meaning of `public` and expanding the use of `open`.  This 
>> provides consistent capabilities and semantics across enums, classes and 
>> protocols.
>> 
>> `open` is the most permissive modifier.  The symbol is visible outside the 
>> module and both users and future versions of the library are allowed to add 
>> new cases, subclasses or conformances.  (Note: this proposal does not 
>> introduce user-extensible `open` enums, but provides the syntax that would 
>> be used if they are added to the language)
>> 
>> `public` makes the symbol visible without allowing the user to add new 
>> cases, subclasses or conformances.  The library reserves the right to add 
>> new cases, subclasses or conformances in a future version.
>> 
>> `closed` is the most restrictive modifier.  The symbol is visible publicly 
>> with 

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-11 Thread Matthew Johnson via swift-evolution

> On Feb 11, 2017, at 7:56 AM, Karl Wagner  wrote:
> 
> 
>> On 11 Feb 2017, at 14:37, Karl Wagner > > wrote:
>> 
>> 
>>> On 9 Feb 2017, at 00:05, Matthew Johnson via swift-evolution 
>>> > wrote:
>>> 
>>> I’ve been thinking a lot about our public access modifier story lately in 
>>> the context of both protocols and enums.  I believe we should move further 
>>> in the direction we took when introducing the `open` keyword.  I have 
>>> identified what I think is a promising direction and am interested in 
>>> feedback from the community.  If community feedback is positive I will 
>>> flesh this out into a more complete proposal draft.
>>> 
>>> 
>>> Background and Motivation:
>>> 
>>> In Swift 3 we had an extended debate regarding whether or not to allow 
>>> inheritance of public classes by default or to require an annotation for 
>>> classes that could be subclassed outside the module.  The decision we 
>>> reached was to avoid having a default at all, and instead make `open` an 
>>> access modifier.  The result is library authors are required to consider 
>>> the behavior they wish for each class.  Both behaviors are equally 
>>> convenient (neither is penalized by requiring an additional boilerplate-y 
>>> annotation).
>>> 
>>> A recent thread 
>>> (https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170206/031566.html
>>>  
>>> )
>>>  discussed a similar tradeoff regarding whether public enums should commit 
>>> to a fixed set of cases by default or not.  The current behavior is that 
>>> they *do* commit to a fixed set of cases and there is no option (afaik) to 
>>> modify that behavior.  The Library Evolution document 
>>> (https://github.com/apple/swift/blob/master/docs/LibraryEvolution.rst#enums 
>>> )
>>>  suggests a desire to change this before locking down ABI such that public 
>>> enums *do not* make this commitment by default, and are required to opt-in 
>>> to this behavior using an `@closed` annotation.
>>> 
>>> In the previous discussion I stated a strong preference that closed enums 
>>> *not* be penalized with an additional annotation.  This is because I feel 
>>> pretty strongly that it is a design smell to: 1) expose cases publicly if 
>>> consumers of the API are not expected to switch on them and 2) require 
>>> users to handle unknown future cases if they are likely to switch over the 
>>> cases in correct use of the API.
>>> 
>>> The conclusion I came to in that thread is that we should adopt the same 
>>> strategy as we did with classes: there should not be a default.
>>> 
>>> There have also been several discussions both on the list and via Twitter 
>>> regarding whether or not we should allow closed protocols.  In a recent 
>>> Twitter discussion Joe Groff suggested that we don’t need them because we 
>>> should use an enum when there is a fixed set of conforming types.  There 
>>> are at least two  reasons why I still think we *should* add support for 
>>> closed protocols.
>>> 
>>> As noted above (and in the previous thread in more detail), if the set of 
>>> types (cases) isn’t intended to be fixed (i.e. the library may add new 
>>> types in the future) an enum is likely not a good choice.  Using a closed 
>>> protocol discourages the user from switching and prevents the user from 
>>> adding conformances that are not desired.
>>> 
>>> Another use case supported by closed protocols is a design where users are 
>>> not allowed to conform directly to a protocol, but instead are required to 
>>> conform to one of several protocols which refine the closed protocol.  
>>> Enums are not a substitute for this use case.  The only option is to resort 
>>> to documentation and runtime checks.
>>> 
>>> 
>>> Proposal:
>>> 
>>> This proposal introduces the new access modifier `closed` as well as 
>>> clarifying the meaning of `public` and expanding the use of `open`.  This 
>>> provides consistent capabilities and semantics across enums, classes and 
>>> protocols.
>>> 
>>> `open` is the most permissive modifier.  The symbol is visible outside the 
>>> module and both users and future versions of the library are allowed to add 
>>> new cases, subclasses or conformances.  (Note: this proposal does not 
>>> introduce user-extensible `open` enums, but provides the syntax that would 
>>> be used if they are added to the language)
>>> 
>>> `public` makes the symbol visible without allowing the user to add new 
>>> cases, subclasses or conformances.  The library reserves the right to add 
>>> new cases, subclasses or conformances in a future version.
>>> 
>>> `closed` is the most restrictive modifier.  The symbol is visible publicly 
>>> with the commitment that future versions of the 

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-11 Thread Matthew Johnson via swift-evolution

> On Feb 11, 2017, at 7:37 AM, Karl Wagner  wrote:
> 
> 
>> On 9 Feb 2017, at 00:05, Matthew Johnson via swift-evolution 
>> > wrote:
>> 
>> I’ve been thinking a lot about our public access modifier story lately in 
>> the context of both protocols and enums.  I believe we should move further 
>> in the direction we took when introducing the `open` keyword.  I have 
>> identified what I think is a promising direction and am interested in 
>> feedback from the community.  If community feedback is positive I will flesh 
>> this out into a more complete proposal draft.
>> 
>> 
>> Background and Motivation:
>> 
>> In Swift 3 we had an extended debate regarding whether or not to allow 
>> inheritance of public classes by default or to require an annotation for 
>> classes that could be subclassed outside the module.  The decision we 
>> reached was to avoid having a default at all, and instead make `open` an 
>> access modifier.  The result is library authors are required to consider the 
>> behavior they wish for each class.  Both behaviors are equally convenient 
>> (neither is penalized by requiring an additional boilerplate-y annotation).
>> 
>> A recent thread 
>> (https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170206/031566.html
>>  
>> )
>>  discussed a similar tradeoff regarding whether public enums should commit 
>> to a fixed set of cases by default or not.  The current behavior is that 
>> they *do* commit to a fixed set of cases and there is no option (afaik) to 
>> modify that behavior.  The Library Evolution document 
>> (https://github.com/apple/swift/blob/master/docs/LibraryEvolution.rst#enums 
>> )
>>  suggests a desire to change this before locking down ABI such that public 
>> enums *do not* make this commitment by default, and are required to opt-in 
>> to this behavior using an `@closed` annotation.
>> 
>> In the previous discussion I stated a strong preference that closed enums 
>> *not* be penalized with an additional annotation.  This is because I feel 
>> pretty strongly that it is a design smell to: 1) expose cases publicly if 
>> consumers of the API are not expected to switch on them and 2) require users 
>> to handle unknown future cases if they are likely to switch over the cases 
>> in correct use of the API.
>> 
>> The conclusion I came to in that thread is that we should adopt the same 
>> strategy as we did with classes: there should not be a default.
>> 
>> There have also been several discussions both on the list and via Twitter 
>> regarding whether or not we should allow closed protocols.  In a recent 
>> Twitter discussion Joe Groff suggested that we don’t need them because we 
>> should use an enum when there is a fixed set of conforming types.  There are 
>> at least two  reasons why I still think we *should* add support for closed 
>> protocols.
>> 
>> As noted above (and in the previous thread in more detail), if the set of 
>> types (cases) isn’t intended to be fixed (i.e. the library may add new types 
>> in the future) an enum is likely not a good choice.  Using a closed protocol 
>> discourages the user from switching and prevents the user from adding 
>> conformances that are not desired.
>> 
>> Another use case supported by closed protocols is a design where users are 
>> not allowed to conform directly to a protocol, but instead are required to 
>> conform to one of several protocols which refine the closed protocol.  Enums 
>> are not a substitute for this use case.  The only option is to resort to 
>> documentation and runtime checks.
>> 
>> 
>> Proposal:
>> 
>> This proposal introduces the new access modifier `closed` as well as 
>> clarifying the meaning of `public` and expanding the use of `open`.  This 
>> provides consistent capabilities and semantics across enums, classes and 
>> protocols.
>> 
>> `open` is the most permissive modifier.  The symbol is visible outside the 
>> module and both users and future versions of the library are allowed to add 
>> new cases, subclasses or conformances.  (Note: this proposal does not 
>> introduce user-extensible `open` enums, but provides the syntax that would 
>> be used if they are added to the language)
>> 
>> `public` makes the symbol visible without allowing the user to add new 
>> cases, subclasses or conformances.  The library reserves the right to add 
>> new cases, subclasses or conformances in a future version.
>> 
>> `closed` is the most restrictive modifier.  The symbol is visible publicly 
>> with the commitment that future versions of the library are *also* 
>> prohibited from adding new cases, subclasses or conformances.  Additionally, 
>> all cases, subclasses or conformances must be visible outside the module.
>> 
>> Note: the `closed` 

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-11 Thread Xiaodi Wu via swift-evolution
On Sat, Feb 11, 2017 at 12:53 PM, Matthew Johnson 
wrote:

>
>
> Sent from my iPad
>
> On Feb 11, 2017, at 12:44 PM, Xiaodi Wu  wrote:
>
> On Sat, Feb 11, 2017 at 12:42 PM, Matthew Johnson via swift-evolution <
> swift-evolution@swift.org> wrote:
>
>>
>>
>> Sent from my iPad
>>
>> > On Feb 11, 2017, at 7:22 AM, Rien  wrote:
>> >
>> > I admit that I have not followed all of this discussion, but as far as
>> I see, we could equally well do this by calling “not-open” enum’s “final”.
>> > It seems like a better fit to me.
>>
>> That is actually not a very good fit at all.  `final` means a class
>> cannot have any subclasses.  If we applied it to enums I think the closest
>> parallel would be an enum with no cases.  But this makes the enum
>> uninhabited so it is not just like `final class`, but actually more like
>> `abstract final class`.
>>
>
> Well, you _could_ move `final` to the cases themselves, and it would mean
> the right thing: `enum Foo { final case bar, baz }`.
>
>
> I don't quite follow this.  In order for `final` to mean something when
> applied to a kind of entity it should also be meaningful to non-final
> entities of that same kind.  What would a non-final case be?
>

Yeah, you're right; that doesn't quite cut it.


>> >
>> > Regards,
>> > Rien
>> >
>> > Site: http://balancingrock.nl
>> > Blog: http://swiftrien.blogspot.com
>> > Github: http://github.com/Balancingrock
>> > Project: http://swiftfire.nl
>> >
>> >
>> >
>> >
>> >
>> >> On 11 Feb 2017, at 14:07, Matthew Johnson via swift-evolution <
>> swift-evolution@swift.org> wrote:
>> >>
>> >>
>> >>
>> >> Sent from my iPad
>> >>
>> >>> On Feb 11, 2017, at 4:25 AM, Adrian Zubarev via swift-evolution <
>> swift-evolution@swift.org> wrote:
>> >>>
>> >>> I’m probably better describing things with some bikeshedding code,
>> but feel free to criticize it as much as you’d like.
>> >>>
>> >>> //===- Module A -===//
>> >>> @closed public enum A {
>> >>>case a
>> >>> }
>> >>>
>> >>> extension A {
>> >>>case aa // error, because enum is closed
>> >>> }
>> >>>
>> >> This is an error because you can't add cases in an extension.  I
>> imagine this is how cases would be added outside the module if we allow
>> `open enum` in the future.  But whether or not this is allowed *within* the
>> module is a separate question that is orthogonal to `closed` and `open`.
>> >>
>> >>
>> >>>
>> >>> public func foo(a: A) {
>> >>>switch a {
>> >>>case .a:
>> >>>print("done")
>> >>>}
>> >>> }
>> >>>
>> >>> public enum B {
>> >>>case b
>> >>> }
>> >>>
>> >>> extension B {
>> >>>case bb // fine, because not-closed enums are extensible
>> >>> }
>> >>>
>> >> As noted above, whether this is allowed or not *within* the module is
>> orthogonal to `closed`.  *Outside* the module it would only be possible for
>> enum declared `open` (if we add this feature in the future).
>> >>
>> >>>
>> >>> public func bar(b: B) {
>> >>>switch b {
>> >>>case .b:
>> >>>print("b")
>> >>>
>> >>>default: // always needed
>> >>>print("some other case")
>> >>>}
>> >>> }
>> >>>
>> >>> // Sub-enum relationships
>> >>>
>> >>> // Possible even the enum A is closed, because `@closed` only
>> >>> // closes the extensibility of an enum
>> >>> enum SubA : A {
>> >>>case aa
>> >>> }
>> >>>
>> >>>
>> >> Now you're talking about value subtypes.  That is orthogonal.  Also,
>> this syntax already has a meaning (the raw value of the enum is A) so we
>> wouldn't be able to use it the way you are intending here.  Finally, it is
>> misleading syntax because what you mean here is "A is a subtype of SubA"
>> which is exactly the opposite of what the syntax implies.
>> >>
>> >> All values of A are valid values of SubA, but SubA has values that are
>> not valid values of A.
>> >>
>> >>> // The following enum can have a sub-enum in the clients module
>> >>> open enum C {
>> >>>case c
>> >>> }
>> >>>
>> >>> public func cool(c: C) {
>> >>>switch c {
>> >>>case .c:
>> >>>print("c")
>> >>>
>> >>>default: // always needed
>> >>>print("some other case")
>> >>>}
>> >>> }
>> >>>
>> >>> @closed open enum D {
>> >>>case d
>> >>> }
>> >>>
>> >>> public func doo(d: D) {
>> >>>switch b {
>> >>>case .b:
>> >>>print("b")
>> >>>}
>> >>> }
>> >>>
>> >>> // The enum case is always known at any point, no matter
>> >>> // where the instance comes from, right?
>> >>>
>> >>> let subA = SubA.aa
>> >>> let otherSubA = SubA.a // Inherited case
>> >>>
>> >>> let a: A = subA// error, downgrade the sub-enum to A first
>> >>> let a: A = otherSubA   // okay
>> >>>
>> >>> foo(a: subA)   // error, downgrade the sub-enum to A first
>> >>> foo(a: otherSubA)  // okay
>> >>>
>> >>> //===- Module B -===//
>> >>>
>> >>> // Totally fine
>> >>> switch A.a {
>> >>> case .a:
>> >>>

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-11 Thread Matthew Johnson via swift-evolution


Sent from my iPad

> On Feb 11, 2017, at 12:44 PM, Xiaodi Wu  wrote:
> 
>> On Sat, Feb 11, 2017 at 12:42 PM, Matthew Johnson via swift-evolution 
>>  wrote:
>> 
>> 
>> Sent from my iPad
>> 
>> > On Feb 11, 2017, at 7:22 AM, Rien  wrote:
>> >
>> > I admit that I have not followed all of this discussion, but as far as I 
>> > see, we could equally well do this by calling “not-open” enum’s “final”.
>> > It seems like a better fit to me.
>> 
>> That is actually not a very good fit at all.  `final` means a class cannot 
>> have any subclasses.  If we applied it to enums I think the closest parallel 
>> would be an enum with no cases.  But this makes the enum uninhabited so it 
>> is not just like `final class`, but actually more like `abstract final 
>> class`.
> 
> Well, you _could_ move `final` to the cases themselves, and it would mean the 
> right thing: `enum Foo { final case bar, baz }`.

I don't quite follow this.  In order for `final` to mean something when applied 
to a kind of entity it should also be meaningful to non-final entities of that 
same kind.  What would a non-final case be?

> 
>> 
>> >
>> > Regards,
>> > Rien
>> >
>> > Site: http://balancingrock.nl
>> > Blog: http://swiftrien.blogspot.com
>> > Github: http://github.com/Balancingrock
>> > Project: http://swiftfire.nl
>> >
>> >
>> >
>> >
>> >
>> >> On 11 Feb 2017, at 14:07, Matthew Johnson via swift-evolution 
>> >>  wrote:
>> >>
>> >>
>> >>
>> >> Sent from my iPad
>> >>
>> >>> On Feb 11, 2017, at 4:25 AM, Adrian Zubarev via swift-evolution 
>> >>>  wrote:
>> >>>
>> >>> I’m probably better describing things with some bikeshedding code, but 
>> >>> feel free to criticize it as much as you’d like.
>> >>>
>> >>> //===- Module A -===//
>> >>> @closed public enum A {
>> >>>case a
>> >>> }
>> >>>
>> >>> extension A {
>> >>>case aa // error, because enum is closed
>> >>> }
>> >>>
>> >> This is an error because you can't add cases in an extension.  I imagine 
>> >> this is how cases would be added outside the module if we allow `open 
>> >> enum` in the future.  But whether or not this is allowed *within* the 
>> >> module is a separate question that is orthogonal to `closed` and `open`.
>> >>
>> >>
>> >>>
>> >>> public func foo(a: A) {
>> >>>switch a {
>> >>>case .a:
>> >>>print("done")
>> >>>}
>> >>> }
>> >>>
>> >>> public enum B {
>> >>>case b
>> >>> }
>> >>>
>> >>> extension B {
>> >>>case bb // fine, because not-closed enums are extensible
>> >>> }
>> >>>
>> >> As noted above, whether this is allowed or not *within* the module is 
>> >> orthogonal to `closed`.  *Outside* the module it would only be possible 
>> >> for enum declared `open` (if we add this feature in the future).
>> >>
>> >>>
>> >>> public func bar(b: B) {
>> >>>switch b {
>> >>>case .b:
>> >>>print("b")
>> >>>
>> >>>default: // always needed
>> >>>print("some other case")
>> >>>}
>> >>> }
>> >>>
>> >>> // Sub-enum relationships
>> >>>
>> >>> // Possible even the enum A is closed, because `@closed` only
>> >>> // closes the extensibility of an enum
>> >>> enum SubA : A {
>> >>>case aa
>> >>> }
>> >>>
>> >>>
>> >> Now you're talking about value subtypes.  That is orthogonal.  Also, this 
>> >> syntax already has a meaning (the raw value of the enum is A) so we 
>> >> wouldn't be able to use it the way you are intending here.  Finally, it 
>> >> is misleading syntax because what you mean here is "A is a subtype of 
>> >> SubA" which is exactly the opposite of what the syntax implies.
>> >>
>> >> All values of A are valid values of SubA, but SubA has values that are 
>> >> not valid values of A.
>> >>
>> >>> // The following enum can have a sub-enum in the clients module
>> >>> open enum C {
>> >>>case c
>> >>> }
>> >>>
>> >>> public func cool(c: C) {
>> >>>switch c {
>> >>>case .c:
>> >>>print("c")
>> >>>
>> >>>default: // always needed
>> >>>print("some other case")
>> >>>}
>> >>> }
>> >>>
>> >>> @closed open enum D {
>> >>>case d
>> >>> }
>> >>>
>> >>> public func doo(d: D) {
>> >>>switch b {
>> >>>case .b:
>> >>>print("b")
>> >>>}
>> >>> }
>> >>>
>> >>> // The enum case is always known at any point, no matter
>> >>> // where the instance comes from, right?
>> >>>
>> >>> let subA = SubA.aa
>> >>> let otherSubA = SubA.a // Inherited case
>> >>>
>> >>> let a: A = subA// error, downgrade the sub-enum to A first
>> >>> let a: A = otherSubA   // okay
>> >>>
>> >>> foo(a: subA)   // error, downgrade the sub-enum to A first
>> >>> foo(a: otherSubA)  // okay
>> >>>
>> >>> //===- Module B -===//
>> >>>
>> >>> // Totally fine
>> >>> switch A.a {
>> >>> case .a:
>> >>>print("done")
>> >>> }
>> >>>
>> >>> extension A {
>> >>>case aa // not 

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-11 Thread Adrian Zubarev via swift-evolution
I’m definitely looking forward to this, it’s a highly interesting topic to 
follow. :) Thank you for all your hard work.



-- 
Adrian Zubarev
Sent with Airmail

Am 11. Februar 2017 um 19:47:36, Matthew Johnson (matt...@anandabits.com) 
schrieb:



Sent from my iPad

On Feb 11, 2017, at 12:38 PM, Adrian Zubarev via swift-evolution 
 wrote:

That makes actually sense to me if we think of it that we never will get any 
sub-typing for enums. I’m still undecided on that sub-typing topic about value 
types. Just out of curiosity it would be interesting to hear from the core team 
if this would be a future direction for Swift or not, be it in Swift 20 or 
whatever. :)

The core team has indicated support for value subtyping.  It's unclear when 
this might happen though.

I am working on writing up some ideas related to this right now.  I hope that 
helps you to see how value subtyping fits into the hypothetical Swift with 
`closed` as an access modifier I am proposing.  This will be more of a 
"manifesto" style document than a proposal.  It will lay out the landscape a 
bunch of related ideas, some of which may have ABI impact (and this be relevant 
for consideration now) and others will be left for future consideration.

Back on the original topic: If the community feels we need something like 
closed, then so be it, I don’t mind having flexibility because it makes the 
language more powerful.

We definitely need it for enums.  The only question is how we spell it and 
whether the semantics have a clear and consistent relationship with how we 
treat classes, protocols and the `open` access modifier.  My proposal is that 
we do it in a way that is clear and consistent.



-- 
Adrian Zubarev
Sent with Airmail

Am 11. Februar 2017 um 19:31:10, Xiaodi Wu (xiaodi...@gmail.com) schrieb:

I think Matthew's point (with which I agree) is that, as enums are sum types, 
adding or removing cases is akin to subclassing. You can extend a public enum 
by adding methods just like you can extend a public class. But just as you 
cannot subclass a public class, you should not be able to add or remove cases 
from a public enum.


On Sat, Feb 11, 2017 at 8:37 AM, Adrian Zubarev via swift-evolution 
 wrote:
I have to correct myself here and there.

… which would be extensible if that feature might be added to swift one day.

Again, I see open only as a contract to allow sub-typing, conformances and 
overriding to the client, where extensibility of a type a story of it’s own.


-- 
Adrian Zubarev
Sent with Airmail

Am 11. Februar 2017 um 15:33:17, Adrian Zubarev 
(adrian.zuba...@devandartist.com) schrieb:

It wasn’t my intention to drive to far way off topic with this. The major point 
of my last bike shedding was that I have to disagree with you about the 
potential future open enum vs. public enum and closed enum.

public today does not add any guarantee to prevent the client from extending 
your type. For instance:

// Module A
public class A { public init() {} }

// Module B
extension A {

convenience init(foo: Int) {
print(foo)
self.init()
}
}
That also implies to me that open as an access modifier does not prevent 
extensibility.

Speaking of opened enums, we really do not mean open enum to allow 
extensibility where closed enum would mean the opposite. closed or @closed by 
all the definitions I’ve read so far is what the current public means for 
enums. If this is going to be fixed to closed enum (@closed public enum) than 
what we’re currently speaking of is nothing else than public enum, which would 
be extensible if that future might be added to swift one day.

Again, I see open only as a contract to prevent sub-typing, conformances and 
overriding, where extensibility of a type a story of it’s own.

Quickly compared to protocols: public-but-not-open protocol from module A 
should remain extensible in module B. Consistently that would mean that public 
enum is the enum when we’re talking about future extensibility of that enum 
from the clients side outside your module. You simply should be able to add new 
cases directly to your enum if it’s not annotated as closed. open enum on the 
other hand makes only sense when we’d speak about sub-typing on enums or value 
types in general.



-- 
Adrian Zubarev
Sent with Airmail

Am 11. Februar 2017 um 14:08:02, Matthew Johnson (matt...@anandabits.com) 
schrieb:



Sent from my iPad

On Feb 11, 2017, at 4:25 AM, Adrian Zubarev via swift-evolution 
 wrote:

I’m probably better describing things with some bikeshedding code, but feel 
free to criticize it as much as you’d like.

//===- Module A -===//
@closed public enum A {
case a
}

extension A {
case aa // error, because enum is closed
}
This is an error because you can't add cases in an extension.  I imagine this 
is how cases would be added outside the module if we allow `open 

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-11 Thread Matthew Johnson via swift-evolution


Sent from my iPad

> On Feb 11, 2017, at 12:38 PM, Adrian Zubarev via swift-evolution 
>  wrote:
> 
> That makes actually sense to me if we think of it that we never will get any 
> sub-typing for enums. I’m still undecided on that sub-typing topic about 
> value types. Just out of curiosity it would be interesting to hear from the 
> core team if this would be a future direction for Swift or not, be it in 
> Swift 20 or whatever. :)
> 
The core team has indicated support for value subtyping.  It's unclear when 
this might happen though.

I am working on writing up some ideas related to this right now.  I hope that 
helps you to see how value subtyping fits into the hypothetical Swift with 
`closed` as an access modifier I am proposing.  This will be more of a 
"manifesto" style document than a proposal.  It will lay out the landscape a 
bunch of related ideas, some of which may have ABI impact (and this be relevant 
for consideration now) and others will be left for future consideration.

> Back on the original topic: If the community feels we need something like 
> closed, then so be it, I don’t mind having flexibility because it makes the 
> language more powerful.
> 
We definitely need it for enums.  The only question is how we spell it and 
whether the semantics have a clear and consistent relationship with how we 
treat classes, protocols and the `open` access modifier.  My proposal is that 
we do it in a way that is clear and consistent.

> 
> 
> -- 
> Adrian Zubarev
> Sent with Airmail
> 
> Am 11. Februar 2017 um 19:31:10, Xiaodi Wu (xiaodi...@gmail.com) schrieb:
> 
>> I think Matthew's point (with which I agree) is that, as enums are sum 
>> types, adding or removing cases is akin to subclassing. You can extend a 
>> public enum by adding methods just like you can extend a public class. But 
>> just as you cannot subclass a public class, you should not be able to add or 
>> remove cases from a public enum.
>> 
>> 
>>> On Sat, Feb 11, 2017 at 8:37 AM, Adrian Zubarev via swift-evolution 
>>>  wrote:
>>> I have to correct myself here and there.
>>> 
>>> … which would be extensible if that feature might be added to swift one day.
>>> 
>>> Again, I see open only as a contract to allow sub-typing, conformances and 
>>> overriding to the client, where extensibility of a type a story of it’s own.
>>> 
>>> 
>>> -- 
>>> Adrian Zubarev
>>> Sent with Airmail
>>> 
>>> Am 11. Februar 2017 um 15:33:17, Adrian Zubarev 
>>> (adrian.zuba...@devandartist.com) schrieb:
>>> 
 It wasn’t my intention to drive to far way off topic with this. The major 
 point of my last bike shedding was that I have to disagree with you about 
 the potential future open enum vs. public enum and closed enum.
 
 public today does not add any guarantee to prevent the client from 
 extending your type. For instance:
 
 // Module A
 public class A { public init() {} }
 
 // Module B
 extension A {

 convenience init(foo: Int) {
 print(foo)
 self.init()
 }
 }
 That also implies to me that open as an access modifier does not prevent 
 extensibility.
 
 Speaking of opened enums, we really do not mean open enum to allow 
 extensibility where closed enum would mean the opposite. closed or @closed 
 by all the definitions I’ve read so far is what the current public means 
 for enums. If this is going to be fixed to closed enum (@closed public 
 enum) than what we’re currently speaking of is nothing else than public 
 enum, which would be extensible if that future might be added to swift one 
 day.
 
 Again, I see open only as a contract to prevent sub-typing, conformances 
 and overriding, where extensibility of a type a story of it’s own.
 
 Quickly compared to protocols: public-but-not-open protocol from module A 
 should remain extensible in module B. Consistently that would mean that 
 public enum is the enum when we’re talking about future extensibility of 
 that enum from the clients side outside your module. You simply should be 
 able to add new cases directly to your enum if it’s not annotated as 
 closed. open enum on the other hand makes only sense when we’d speak about 
 sub-typing on enums or value types in general.
 
 
 
 -- 
 Adrian Zubarev
 Sent with Airmail
 
 Am 11. Februar 2017 um 14:08:02, Matthew Johnson (matt...@anandabits.com) 
 schrieb:
 
> 
> 
> Sent from my iPad
> 
> On Feb 11, 2017, at 4:25 AM, Adrian Zubarev via swift-evolution 
>  wrote:
> 
>> I’m probably better describing things with some bikeshedding code, but 
>> feel free to criticize it as much as you’d like.
>> 
>> //===- Module A -===//
>> @closed public enum A {
>> 

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-11 Thread Xiaodi Wu via swift-evolution
On Sat, Feb 11, 2017 at 12:42 PM, Matthew Johnson via swift-evolution <
swift-evolution@swift.org> wrote:

>
>
> Sent from my iPad
>
> > On Feb 11, 2017, at 7:22 AM, Rien  wrote:
> >
> > I admit that I have not followed all of this discussion, but as far as I
> see, we could equally well do this by calling “not-open” enum’s “final”.
> > It seems like a better fit to me.
>
> That is actually not a very good fit at all.  `final` means a class cannot
> have any subclasses.  If we applied it to enums I think the closest
> parallel would be an enum with no cases.  But this makes the enum
> uninhabited so it is not just like `final class`, but actually more like
> `abstract final class`.
>

Well, you _could_ move `final` to the cases themselves, and it would mean
the right thing: `enum Foo { final case bar, baz }`.


> >
> > Regards,
> > Rien
> >
> > Site: http://balancingrock.nl
> > Blog: http://swiftrien.blogspot.com
> > Github: http://github.com/Balancingrock
> > Project: http://swiftfire.nl
> >
> >
> >
> >
> >
> >> On 11 Feb 2017, at 14:07, Matthew Johnson via swift-evolution <
> swift-evolution@swift.org> wrote:
> >>
> >>
> >>
> >> Sent from my iPad
> >>
> >>> On Feb 11, 2017, at 4:25 AM, Adrian Zubarev via swift-evolution <
> swift-evolution@swift.org> wrote:
> >>>
> >>> I’m probably better describing things with some bikeshedding code, but
> feel free to criticize it as much as you’d like.
> >>>
> >>> //===- Module A -===//
> >>> @closed public enum A {
> >>>case a
> >>> }
> >>>
> >>> extension A {
> >>>case aa // error, because enum is closed
> >>> }
> >>>
> >> This is an error because you can't add cases in an extension.  I
> imagine this is how cases would be added outside the module if we allow
> `open enum` in the future.  But whether or not this is allowed *within* the
> module is a separate question that is orthogonal to `closed` and `open`.
> >>
> >>
> >>>
> >>> public func foo(a: A) {
> >>>switch a {
> >>>case .a:
> >>>print("done")
> >>>}
> >>> }
> >>>
> >>> public enum B {
> >>>case b
> >>> }
> >>>
> >>> extension B {
> >>>case bb // fine, because not-closed enums are extensible
> >>> }
> >>>
> >> As noted above, whether this is allowed or not *within* the module is
> orthogonal to `closed`.  *Outside* the module it would only be possible for
> enum declared `open` (if we add this feature in the future).
> >>
> >>>
> >>> public func bar(b: B) {
> >>>switch b {
> >>>case .b:
> >>>print("b")
> >>>
> >>>default: // always needed
> >>>print("some other case")
> >>>}
> >>> }
> >>>
> >>> // Sub-enum relationships
> >>>
> >>> // Possible even the enum A is closed, because `@closed` only
> >>> // closes the extensibility of an enum
> >>> enum SubA : A {
> >>>case aa
> >>> }
> >>>
> >>>
> >> Now you're talking about value subtypes.  That is orthogonal.  Also,
> this syntax already has a meaning (the raw value of the enum is A) so we
> wouldn't be able to use it the way you are intending here.  Finally, it is
> misleading syntax because what you mean here is "A is a subtype of SubA"
> which is exactly the opposite of what the syntax implies.
> >>
> >> All values of A are valid values of SubA, but SubA has values that are
> not valid values of A.
> >>
> >>> // The following enum can have a sub-enum in the clients module
> >>> open enum C {
> >>>case c
> >>> }
> >>>
> >>> public func cool(c: C) {
> >>>switch c {
> >>>case .c:
> >>>print("c")
> >>>
> >>>default: // always needed
> >>>print("some other case")
> >>>}
> >>> }
> >>>
> >>> @closed open enum D {
> >>>case d
> >>> }
> >>>
> >>> public func doo(d: D) {
> >>>switch b {
> >>>case .b:
> >>>print("b")
> >>>}
> >>> }
> >>>
> >>> // The enum case is always known at any point, no matter
> >>> // where the instance comes from, right?
> >>>
> >>> let subA = SubA.aa
> >>> let otherSubA = SubA.a // Inherited case
> >>>
> >>> let a: A = subA// error, downgrade the sub-enum to A first
> >>> let a: A = otherSubA   // okay
> >>>
> >>> foo(a: subA)   // error, downgrade the sub-enum to A first
> >>> foo(a: otherSubA)  // okay
> >>>
> >>> //===- Module B -===//
> >>>
> >>> // Totally fine
> >>> switch A.a {
> >>> case .a:
> >>>print("done")
> >>> }
> >>>
> >>> extension A {
> >>>case aa // not allowed because the enum is closed
> >>> }
> >>>
> >>> extension B {
> >>>case bbb
> >>> }
> >>>
> >>> switch B.b {
> >>> case .b:
> >>>print("b")
> >>> default:
> >>>print("somethine else")
> >>> }
> >>>
> >>> bar(b: B.bbb) // fine, because the switch statement on enums without
> >>> // `@closed` has always`default`
> >>>
> >>> // Allowed because `C` is open, and open allows sub-typing, conforming
> >>> // and overriding to the client
> >>> enum SubC : C {
> >>>case cc
> >>> }
> >>>
> >>> let subC =
> >>> SubC.cc
> 

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-11 Thread Matthew Johnson via swift-evolution


Sent from my iPad

> On Feb 11, 2017, at 7:22 AM, Rien  wrote:
> 
> I admit that I have not followed all of this discussion, but as far as I see, 
> we could equally well do this by calling “not-open” enum’s “final”.
> It seems like a better fit to me.

That is actually not a very good fit at all.  `final` means a class cannot have 
any subclasses.  If we applied it to enums I think the closest parallel would 
be an enum with no cases.  But this makes the enum uninhabited so it is not 
just like `final class`, but actually more like `abstract final class`.

> 
> Regards,
> Rien
> 
> Site: http://balancingrock.nl
> Blog: http://swiftrien.blogspot.com
> Github: http://github.com/Balancingrock
> Project: http://swiftfire.nl
> 
> 
> 
> 
> 
>> On 11 Feb 2017, at 14:07, Matthew Johnson via swift-evolution 
>>  wrote:
>> 
>> 
>> 
>> Sent from my iPad
>> 
>>> On Feb 11, 2017, at 4:25 AM, Adrian Zubarev via swift-evolution 
>>>  wrote:
>>> 
>>> I’m probably better describing things with some bikeshedding code, but feel 
>>> free to criticize it as much as you’d like.
>>> 
>>> //===- Module A -===//
>>> @closed public enum A {
>>>case a
>>> }
>>> 
>>> extension A {
>>>case aa // error, because enum is closed
>>> }
>>> 
>> This is an error because you can't add cases in an extension.  I imagine 
>> this is how cases would be added outside the module if we allow `open enum` 
>> in the future.  But whether or not this is allowed *within* the module is a 
>> separate question that is orthogonal to `closed` and `open`.
>> 
>> 
>>> 
>>> public func foo(a: A) {
>>>switch a {
>>>case .a:
>>>print("done")
>>>}
>>> }
>>> 
>>> public enum B {
>>>case b
>>> }
>>> 
>>> extension B {
>>>case bb // fine, because not-closed enums are extensible
>>> }
>>> 
>> As noted above, whether this is allowed or not *within* the module is 
>> orthogonal to `closed`.  *Outside* the module it would only be possible for 
>> enum declared `open` (if we add this feature in the future).
>> 
>>> 
>>> public func bar(b: B) {
>>>switch b {
>>>case .b:
>>>print("b")
>>> 
>>>default: // always needed
>>>print("some other case")
>>>}
>>> }
>>> 
>>> // Sub-enum relationships
>>> 
>>> // Possible even the enum A is closed, because `@closed` only  
>>> // closes the extensibility of an enum
>>> enum SubA : A {
>>>case aa
>>> }
>>> 
>>> 
>> Now you're talking about value subtypes.  That is orthogonal.  Also, this 
>> syntax already has a meaning (the raw value of the enum is A) so we wouldn't 
>> be able to use it the way you are intending here.  Finally, it is misleading 
>> syntax because what you mean here is "A is a subtype of SubA" which is 
>> exactly the opposite of what the syntax implies.
>> 
>> All values of A are valid values of SubA, but SubA has values that are not 
>> valid values of A.
>> 
>>> // The following enum can have a sub-enum in the clients module
>>> open enum C {
>>>case c
>>> }
>>> 
>>> public func cool(c: C) {
>>>switch c {
>>>case .c:
>>>print("c")
>>> 
>>>default: // always needed
>>>print("some other case")
>>>}
>>> }
>>> 
>>> @closed open enum D {
>>>case d
>>> }
>>> 
>>> public func doo(d: D) {
>>>switch b {
>>>case .b:
>>>print("b")
>>>}
>>> }
>>> 
>>> // The enum case is always known at any point, no matter  
>>> // where the instance comes from, right?
>>> 
>>> let subA = SubA.aa
>>> let otherSubA = SubA.a // Inherited case
>>> 
>>> let a: A = subA// error, downgrade the sub-enum to A first
>>> let a: A = otherSubA   // okay
>>> 
>>> foo(a: subA)   // error, downgrade the sub-enum to A first
>>> foo(a: otherSubA)  // okay
>>> 
>>> //===- Module B -===//
>>> 
>>> // Totally fine  
>>> switch A.a {
>>> case .a:
>>>print("done")
>>> }
>>> 
>>> extension A {
>>>case aa // not allowed because the enum is closed
>>> }
>>> 
>>> extension B {
>>>case bbb
>>> }
>>> 
>>> switch B.b {
>>> case .b:
>>>print("b")
>>> default:  
>>>print("somethine else")
>>> }
>>> 
>>> bar(b: B.bbb) // fine, because the switch statement on enums without  
>>> // `@closed` has always`default`
>>> 
>>> // Allowed because `C` is open, and open allows sub-typing, conforming  
>>> // and overriding to the client
>>> enum SubC : C {
>>>case cc
>>> }
>>> 
>>> let subC = 
>>> SubC.cc
>>> 
>>> 
>>> cool(c: subC) // okay
>>> 
>>> enum SubD : D {
>>>case dd
>>> }
>>> 
>>> doo(d: D.dd)// error, downgrade sub-enum to D first
>>> 
>>> My point here is, that we should not think of (possible) open enums as 
>>> enums that the client is allowed to extend. That way we’re only creating 
>>> another inconsistent case for the open access modifier. As far as I can 
>>> tell, open as for today means “the client is allowed to subclass/override 
>>> things 

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-11 Thread Xiaodi Wu via swift-evolution
On Sat, Feb 11, 2017 at 6:41 AM, Matthew Johnson 
wrote:

>
>
> Sent from my iPad
>
> On Feb 10, 2017, at 9:48 PM, Xiaodi Wu  wrote:
>
> On Wed, Feb 8, 2017 at 5:05 PM, Matthew Johnson via swift-evolution <
> swift-evolution@swift.org> wrote:
>
>> I’ve been thinking a lot about our public access modifier story lately in
>> the context of both protocols and enums.  I believe we should move further
>> in the direction we took when introducing the `open` keyword.  I have
>> identified what I think is a promising direction and am interested in
>> feedback from the community.  If community feedback is positive I will
>> flesh this out into a more complete proposal draft.
>>
>>
>> Background and Motivation:
>>
>> In Swift 3 we had an extended debate regarding whether or not to allow
>> inheritance of public classes by default or to require an annotation for
>> classes that could be subclassed outside the module.  The decision we
>> reached was to avoid having a default at all, and instead make `open` an
>> access modifier.  The result is library authors are required to consider
>> the behavior they wish for each class.  Both behaviors are equally
>> convenient (neither is penalized by requiring an additional boilerplate-y
>> annotation).
>>
>> A recent thread (https://lists.swift.org/piper
>> mail/swift-evolution/Week-of-Mon-20170206/031566.html) discussed a
>> similar tradeoff regarding whether public enums should commit to a fixed
>> set of cases by default or not.  The current behavior is that they *do*
>> commit to a fixed set of cases and there is no option (afaik) to modify
>> that behavior.  The Library Evolution document (
>> https://github.com/apple/swift/blob/master/docs/LibraryEvol
>> ution.rst#enums) suggests a desire to change this before locking down
>> ABI such that public enums *do not* make this commitment by default, and
>> are required to opt-in to this behavior using an `@closed` annotation.
>>
>> In the previous discussion I stated a strong preference that closed enums
>> *not* be penalized with an additional annotation.  This is because I feel
>> pretty strongly that it is a design smell to: 1) expose cases publicly if
>> consumers of the API are not expected to switch on them and 2) require
>> users to handle unknown future cases if they are likely to switch over the
>> cases in correct use of the API.
>>
>> The conclusion I came to in that thread is that we should adopt the same
>> strategy as we did with classes: there should not be a default.
>>
>> There have also been several discussions both on the list and via Twitter
>> regarding whether or not we should allow closed protocols.  In a recent
>> Twitter discussion Joe Groff suggested that we don’t need them because we
>> should use an enum when there is a fixed set of conforming types.  There
>> are at least two  reasons why I still think we *should* add support for
>> closed protocols.
>>
>> As noted above (and in the previous thread in more detail), if the set of
>> types (cases) isn’t intended to be fixed (i.e. the library may add new
>> types in the future) an enum is likely not a good choice.  Using a closed
>> protocol discourages the user from switching and prevents the user from
>> adding conformances that are not desired.
>>
>> Another use case supported by closed protocols is a design where users
>> are not allowed to conform directly to a protocol, but instead are required
>> to conform to one of several protocols which refine the closed protocol.
>> Enums are not a substitute for this use case.  The only option is to resort
>> to documentation and runtime checks.
>>
>>
>> Proposal:
>>
>> This proposal introduces the new access modifier `closed` as well as
>> clarifying the meaning of `public` and expanding the use of `open`.  This
>> provides consistent capabilities and semantics across enums, classes and
>> protocols.
>>
>> `open` is the most permissive modifier.  The symbol is visible outside
>> the module and both users and future versions of the library are allowed to
>> add new cases, subclasses or conformances.  (Note: this proposal does not
>> introduce user-extensible `open` enums, but provides the syntax that would
>> be used if they are added to the language)
>>
>> `public` makes the symbol visible without allowing the user to add new
>> cases, subclasses or conformances.  The library reserves the right to add
>> new cases, subclasses or conformances in a future version.
>>
>> `closed` is the most restrictive modifier.  The symbol is visible
>> publicly with the commitment that future versions of the library are *also*
>> prohibited from adding new cases, subclasses or conformances.
>> Additionally, all cases, subclasses or conformances must be visible outside
>> the module.
>>
>> Note: the `closed` modifier only applies to *direct* subclasses or
>> conformances.  A subclass of a `closed` class need not be `closed`, in fact
>> it may be `open` if the design of the 

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-11 Thread Adrian Zubarev via swift-evolution
That makes actually sense to me if we think of it that we never will get any 
sub-typing for enums. I’m still undecided on that sub-typing topic about value 
types. Just out of curiosity it would be interesting to hear from the core team 
if this would be a future direction for Swift or not, be it in Swift 20 or 
whatever. :)

Back on the original topic: If the community feels we need something like 
closed, then so be it, I don’t mind having flexibility because it makes the 
language more powerful.



-- 
Adrian Zubarev
Sent with Airmail

Am 11. Februar 2017 um 19:31:10, Xiaodi Wu (xiaodi...@gmail.com) schrieb:

I think Matthew's point (with which I agree) is that, as enums are sum types, 
adding or removing cases is akin to subclassing. You can extend a public enum 
by adding methods just like you can extend a public class. But just as you 
cannot subclass a public class, you should not be able to add or remove cases 
from a public enum.


On Sat, Feb 11, 2017 at 8:37 AM, Adrian Zubarev via swift-evolution 
 wrote:
I have to correct myself here and there.

… which would be extensible if that feature might be added to swift one day.

Again, I see open only as a contract to allow sub-typing, conformances and 
overriding to the client, where extensibility of a type a story of it’s own.


-- 
Adrian Zubarev
Sent with Airmail

Am 11. Februar 2017 um 15:33:17, Adrian Zubarev 
(adrian.zuba...@devandartist.com) schrieb:

It wasn’t my intention to drive to far way off topic with this. The major point 
of my last bike shedding was that I have to disagree with you about the 
potential future open enum vs. public enum and closed enum.

public today does not add any guarantee to prevent the client from extending 
your type. For instance:

// Module A
public class A { public init() {} }

// Module B
extension A {
   
convenience init(foo: Int) {
print(foo)
self.init()
}
}
That also implies to me that open as an access modifier does not prevent 
extensibility.

Speaking of opened enums, we really do not mean open enum to allow 
extensibility where closed enum would mean the opposite. closed or @closed by 
all the definitions I’ve read so far is what the current public means for 
enums. If this is going to be fixed to closed enum (@closed public enum) than 
what we’re currently speaking of is nothing else than public enum, which would 
be extensible if that future might be added to swift one day.

Again, I see open only as a contract to prevent sub-typing, conformances and 
overriding, where extensibility of a type a story of it’s own.

Quickly compared to protocols: public-but-not-open protocol from module A 
should remain extensible in module B. Consistently that would mean that public 
enum is the enum when we’re talking about future extensibility of that enum 
from the clients side outside your module. You simply should be able to add new 
cases directly to your enum if it’s not annotated as closed. open enum on the 
other hand makes only sense when we’d speak about sub-typing on enums or value 
types in general.



-- 
Adrian Zubarev
Sent with Airmail

Am 11. Februar 2017 um 14:08:02, Matthew Johnson (matt...@anandabits.com) 
schrieb:



Sent from my iPad

On Feb 11, 2017, at 4:25 AM, Adrian Zubarev via swift-evolution 
 wrote:

I’m probably better describing things with some bikeshedding code, but feel 
free to criticize it as much as you’d like.

//===- Module A -===//
@closed public enum A {
case a
}

extension A {
case aa // error, because enum is closed
}
This is an error because you can't add cases in an extension.  I imagine this 
is how cases would be added outside the module if we allow `open enum` in the 
future.  But whether or not this is allowed *within* the module is a separate 
question that is orthogonal to `closed` and `open`.


  
public func foo(a: A) {
switch a {
case .a:
print("done")
}
}

public enum B {
case b
}

extension B {
case bb // fine, because not-closed enums are extensible
}
As noted above, whether this is allowed or not *within* the module is 
orthogonal to `closed`.  *Outside* the module it would only be possible for 
enum declared `open` (if we add this feature in the future).

  
public func bar(b: B) {
switch b {
case .b:
print("b")

default: // always needed
print("some other case")
}
}

// Sub-enum relationships

// Possible even the enum A is closed, because `@closed` only 
// closes the extensibility of an enum
enum SubA : A {
case aa
}

Now you're talking about value subtypes.  That is orthogonal.  Also, this 
syntax already has a meaning (the raw value of the enum is A) so we wouldn't be 
able to use it the way you are intending here.  Finally, it is misleading 
syntax because what you mean here is "A is a subtype of SubA" which is exactly 
the opposite of what the syntax implies.


Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-11 Thread Matthew Johnson via swift-evolution


Sent from my iPad

> On Feb 11, 2017, at 12:30 PM, Xiaodi Wu  wrote:
> 
> I think Matthew's point (with which I agree) is that, as enums are sum types, 
> adding or removing cases is akin to subclassing. You can extend a public enum 
> by adding methods just like you can extend a public class. But just as you 
> cannot subclass a public class, you should not be able to add or remove cases 
> from a public enum.

Yes, this is exactly the point I am making.  I am working on writing up some 
ideas around value subtyping as well.  I think (hope) that document will make 
the similarity of cases and subclasses more clear for those who don't quite see 
it yet.

> 
> 
>> On Sat, Feb 11, 2017 at 8:37 AM, Adrian Zubarev via swift-evolution 
>>  wrote:
>> I have to correct myself here and there.
>> 
>> … which would be extensible if that feature might be added to swift one day.
>> 
>> Again, I see open only as a contract to allow sub-typing, conformances and 
>> overriding to the client, where extensibility of a type a story of it’s own.
>> 
>> 
>> 
>> -- 
>> Adrian Zubarev
>> Sent with Airmail
>> 
>> Am 11. Februar 2017 um 15:33:17, Adrian Zubarev 
>> (adrian.zuba...@devandartist.com) schrieb:
>> 
>>> It wasn’t my intention to drive to far way off topic with this. The major 
>>> point of my last bike shedding was that I have to disagree with you about 
>>> the potential future open enum vs. public enum and closed enum.
>>> 
>>> public today does not add any guarantee to prevent the client from 
>>> extending your type. For instance:
>>> 
>>> // Module A
>>> public class A { public init() {} }
>>> 
>>> // Module B
>>> extension A {
>>>   
>>> convenience init(foo: Int) {
>>> print(foo)
>>> self.init()
>>> }
>>> }
>>> That also implies to me that open as an access modifier does not prevent 
>>> extensibility.
>>> 
>>> Speaking of opened enums, we really do not mean open enum to allow 
>>> extensibility where closed enum would mean the opposite. closed or @closed 
>>> by all the definitions I’ve read so far is what the current public means 
>>> for enums. If this is going to be fixed to closed enum (@closed public 
>>> enum) than what we’re currently speaking of is nothing else than public 
>>> enum, which would be extensible if that future might be added to swift one 
>>> day.
>>> 
>>> Again, I see open only as a contract to prevent sub-typing, conformances 
>>> and overriding, where extensibility of a type a story of it’s own.
>>> 
>>> Quickly compared to protocols: public-but-not-open protocol from module A 
>>> should remain extensible in module B. Consistently that would mean that 
>>> public enum is the enum when we’re talking about future extensibility of 
>>> that enum from the clients side outside your module. You simply should be 
>>> able to add new cases directly to your enum if it’s not annotated as 
>>> closed. open enum on the other hand makes only sense when we’d speak about 
>>> sub-typing on enums or value types in general.
>>> 
>>> 
>>> 
>>> -- 
>>> Adrian Zubarev
>>> Sent with Airmail
>>> 
>>> Am 11. Februar 2017 um 14:08:02, Matthew Johnson (matt...@anandabits.com) 
>>> schrieb:
>>> 
 
 
 Sent from my iPad
 
 On Feb 11, 2017, at 4:25 AM, Adrian Zubarev via swift-evolution 
  wrote:
 
> I’m probably better describing things with some bikeshedding code, but 
> feel free to criticize it as much as you’d like.
> 
> //===- Module A -===//
> @closed public enum A {
> case a
> }
> 
> extension A {
> case aa // error, because enum is closed
> }
 This is an error because you can't add cases in an extension.  I imagine 
 this is how cases would be added outside the module if we allow `open 
 enum` in the future.  But whether or not this is allowed *within* the 
 module is a separate question that is orthogonal to `closed` and `open`.
 
 
> 
> public func foo(a: A) {
> switch a {
> case .a:
> print("done")
> }
> }
> 
> public enum B {
> case b
> }
> 
> extension B {
> case bb // fine, because not-closed enums are extensible
> }
 As noted above, whether this is allowed or not *within* the module is 
 orthogonal to `closed`.  *Outside* the module it would only be possible 
 for enum declared `open` (if we add this feature in the future).
 
> 
> public func bar(b: B) {
> switch b {
> case .b:
> print("b")
> 
> default: // always needed
> print("some other case")
> }
> }
> 
> // Sub-enum relationships
> 
> // Possible even the enum A is closed, because `@closed` only
> // closes the extensibility of an enum
> enum SubA : A {
> case aa
> }
> 
 Now you're 

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-11 Thread Xiaodi Wu via swift-evolution
I think Matthew's point (with which I agree) is that, as enums are sum
types, adding or removing cases is akin to subclassing. You can extend a
public enum by adding methods just like you can extend a public class. But
just as you cannot subclass a public class, you should not be able to add
or remove cases from a public enum.


On Sat, Feb 11, 2017 at 8:37 AM, Adrian Zubarev via swift-evolution <
swift-evolution@swift.org> wrote:

> I have to correct myself here and there.
>
> … which would be extensible if that feature might be added to swift one
> day.
>
> Again, I see open only as a contract to *allow* sub-typing, conformances
> and overriding to the client, where extensibility of a type a story of it’s
> own.
>
>
>
> --
> Adrian Zubarev
> Sent with Airmail
>
> Am 11. Februar 2017 um 15:33:17, Adrian Zubarev (
> adrian.zuba...@devandartist.com) schrieb:
>
> It wasn’t my intention to drive to far way off topic with this. The major
> point of my last bike shedding was that I have to disagree with you about
> the potential future open enum vs. public enum and closed enum.
>
> public today does not add any guarantee to prevent the client from
> extending your type. For instance:
>
> // Module A
> public class A { public init() {} }
>
> // Module B
> extension A {
>
> convenience init(foo: Int) {
> print(foo)
> self.init()
> }
> }
>
> That also implies to me that open as an access modifier does not prevent
> extensibility.
>
> Speaking of opened enums, we really do not mean open enum to allow
> extensibility where closed enum would mean the opposite. closed or @closed
> by all the definitions I’ve read so far is what the current public means
> for enums. If this is going to be fixed to closed enum (@closed public
> enum) than what we’re currently speaking of is nothing else than public
> enum, which would be extensible if that future might be added to swift
> one day.
>
> Again, I see open only as a contract to prevent sub-typing, conformances
> and overriding, where extensibility of a type a story of it’s own.
>
> Quickly compared to protocols: public-but-not-open protocol from module A
> should remain extensible in module B. Consistently that would mean that public
> enum is the enum when we’re talking about future extensibility of that
> enum from the clients side outside your module. You simply should be able
> to add new cases directly to your enum if it’s not annotated as closed. open
> enum on the other hand makes only sense when we’d speak about sub-typing
> on enums or value types in general.
>
>
> --
> Adrian Zubarev
> Sent with Airmail
>
> Am 11. Februar 2017 um 14:08:02, Matthew Johnson (matt...@anandabits.com)
> schrieb:
>
>
>
> Sent from my iPad
>
> On Feb 11, 2017, at 4:25 AM, Adrian Zubarev via swift-evolution <
> swift-evolution@swift.org> wrote:
>
> I’m probably better describing things with some bikeshedding code, but
> feel free to criticize it as much as you’d like.
>
> //===- Module A -===//
> @closed public enum A {
> case a
> }
>
> extension A {
> case aa // error, because enum is closed
> }
>
> This is an error because you can't add cases in an extension.  I imagine
> this is how cases would be added outside the module if we allow `open enum`
> in the future.  But whether or not this is allowed *within* the module is a
> separate question that is orthogonal to `closed` and `open`.
>
>
>
> public func foo(a: A) {
> switch a {
> case .a:
> print("done")
> }
> }
>
> public enum B {
> case b
> }
>
> extension B {
> case bb // fine, because not-closed enums are extensible
> }
>
> As noted above, whether this is allowed or not *within* the module is
> orthogonal to `closed`.  *Outside* the module it would only be possible for
> enum declared `open` (if we add this feature in the future).
>
>
> public func bar(b: B) {
> switch b {
> case .b:
> print("b")
>
> default: // always needed
> print("some other case")
> }
> }
>
> // Sub-enum relationships
>
> // Possible even the enum A is closed, because `@closed` only
> // closes the extensibility of an enum
> enum SubA : A {
> case aa
> }
>
>
> Now you're talking about value subtypes.  That is orthogonal.  Also, this
> syntax already has a meaning (the raw value of the enum is A) so we
> wouldn't be able to use it the way you are intending here.  Finally, it is
> misleading syntax because what you mean here is "A is a subtype of SubA"
> which is exactly the opposite of what the syntax implies.
>
> All values of A are valid values of SubA, but SubA has values that are not
> valid values of A.
>
> // The following enum can have a sub-enum in the clients module
> open enum C {
> case c
> }
>
> public func cool(c: C) {
> switch c {
> case .c:
> print("c")
>
> default: // always needed
> print("some other case")
> }
> }
>
> @closed open enum D {
> case d
> }
>
> public func doo(d: D) 

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-11 Thread Adrian Zubarev via swift-evolution
I have to correct myself here and there.

… which would be extensible if that feature might be added to swift one day.

Again, I see open only as a contract to allow sub-typing, conformances and 
overriding to the client, where extensibility of a type a story of it’s own.


-- 
Adrian Zubarev
Sent with Airmail

Am 11. Februar 2017 um 15:33:17, Adrian Zubarev 
(adrian.zuba...@devandartist.com) schrieb:

It wasn’t my intention to drive to far way off topic with this. The major point 
of my last bike shedding was that I have to disagree with you about the 
potential future open enum vs. public enum and closed enum.

public today does not add any guarantee to prevent the client from extending 
your type. For instance:

// Module A
public class A { public init() {} }

// Module B
extension A {
  
convenience init(foo: Int) {
print(foo)
self.init()
}
}
That also implies to me that open as an access modifier does not prevent 
extensibility.

Speaking of opened enums, we really do not mean open enum to allow 
extensibility where closed enum would mean the opposite. closed or @closed by 
all the definitions I’ve read so far is what the current public means for 
enums. If this is going to be fixed to closed enum (@closed public enum) than 
what we’re currently speaking of is nothing else than public enum, which would 
be extensible if that future might be added to swift one day.

Again, I see open only as a contract to prevent sub-typing, conformances and 
overriding, where extensibility of a type a story of it’s own.

Quickly compared to protocols: public-but-not-open protocol from module A 
should remain extensible in module B. Consistently that would mean that public 
enum is the enum when we’re talking about future extensibility of that enum 
from the clients side outside your module. You simply should be able to add new 
cases directly to your enum if it’s not annotated as closed. open enum on the 
other hand makes only sense when we’d speak about sub-typing on enums or value 
types in general.



-- 
Adrian Zubarev
Sent with Airmail

Am 11. Februar 2017 um 14:08:02, Matthew Johnson (matt...@anandabits.com) 
schrieb:



Sent from my iPad

On Feb 11, 2017, at 4:25 AM, Adrian Zubarev via swift-evolution 
 wrote:

I’m probably better describing things with some bikeshedding code, but feel 
free to criticize it as much as you’d like.

//===- Module A -===//
@closed public enum A {
case a
}

extension A {
case aa // error, because enum is closed
}
This is an error because you can't add cases in an extension.  I imagine this 
is how cases would be added outside the module if we allow `open enum` in the 
future.  But whether or not this is allowed *within* the module is a separate 
question that is orthogonal to `closed` and `open`.


  
public func foo(a: A) {
switch a {
case .a:
print("done")
}
}

public enum B {
case b
}

extension B {
case bb // fine, because not-closed enums are extensible
}
As noted above, whether this is allowed or not *within* the module is 
orthogonal to `closed`.  *Outside* the module it would only be possible for 
enum declared `open` (if we add this feature in the future).

  
public func bar(b: B) {
switch b {
case .b:
print("b")

default: // always needed
print("some other case")
}
}

// Sub-enum relationships

// Possible even the enum A is closed, because `@closed` only
// closes the extensibility of an enum
enum SubA : A {
case aa
}

Now you're talking about value subtypes.  That is orthogonal.  Also, this 
syntax already has a meaning (the raw value of the enum is A) so we wouldn't be 
able to use it the way you are intending here.  Finally, it is misleading 
syntax because what you mean here is "A is a subtype of SubA" which is exactly 
the opposite of what the syntax implies.

All values of A are valid values of SubA, but SubA has values that are not 
valid values of A.

 // The following enum can have a sub-enum in the clients module
open enum C {
case c
}
public func cool(c: C) {
switch c {
case .c:
print("c")

default: // always needed
print("some other case")
}
}

@closed open enum D {
case d
}

public func doo(d: D) {
switch b {
case .b:
print("b")
}
}

// The enum case is always known at any point, no matter
// where the instance comes from, right?

let subA = SubA.aa
let otherSubA = SubA.a // Inherited case

let a: A = subA// error, downgrade the sub-enum to A first
let a: A = otherSubA   // okay

foo(a: subA)   // error, downgrade the sub-enum to A first
foo(a: otherSubA)  // okay

//===- Module B -===//

// Totally fine
switch A.a {
case .a:
print("done")
}

extension A {
case aa // not allowed because the enum is closed
}

extension B {
case bbb
}

switch B.b {
case .b:

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-11 Thread Adrian Zubarev via swift-evolution
It wasn’t my intention to drive to far way off topic with this. The major point 
of my last bike shedding was that I have to disagree with you about the 
potential future open enum vs. public enum and closed enum.

public today does not add any guarantee to prevent the client from extending 
your type. For instance:

// Module A
public class A { public init() {} }

// Module B
extension A {
 
convenience init(foo: Int) {
print(foo)
self.init()
}
}
That also implies to me that open as an access modifier does not prevent 
extensibility.

Speaking of opened enums, we really do not mean open enum to allow 
extensibility where closed enum would mean the opposite. closed or @closed by 
all the definitions I’ve read so far is what the current public means for 
enums. If this is going to be fixed to closed enum (@closed public enum) than 
what we’re currently speaking of is nothing else than public enum, which would 
be extensible if that future might be added to swift one day.

Again, I see open only as a contract to prevent sub-typing, conformances and 
overriding, where extensibility of a type a story of it’s own.

Quickly compared to protocols: public-but-not-open protocol from module A 
should remain extensible in module B. Consistently that would mean that public 
enum is the enum when we’re talking about future extensibility of that enum 
from the clients side outside your module. You simply should be able to add new 
cases directly to your enum if it’s not annotated as closed. open enum on the 
other hand makes only sense when we’d speak about sub-typing on enums or value 
types in general.



-- 
Adrian Zubarev
Sent with Airmail

Am 11. Februar 2017 um 14:08:02, Matthew Johnson (matt...@anandabits.com) 
schrieb:



Sent from my iPad

On Feb 11, 2017, at 4:25 AM, Adrian Zubarev via swift-evolution 
 wrote:

I’m probably better describing things with some bikeshedding code, but feel 
free to criticize it as much as you’d like.

//===- Module A -===//
@closed public enum A {
case a
}

extension A {
case aa // error, because enum is closed
}
This is an error because you can't add cases in an extension.  I imagine this 
is how cases would be added outside the module if we allow `open enum` in the 
future.  But whether or not this is allowed *within* the module is a separate 
question that is orthogonal to `closed` and `open`.



public func foo(a: A) {
switch a {
case .a:
print("done")
}
}

public enum B {
case b
}

extension B {
case bb // fine, because not-closed enums are extensible
}
As noted above, whether this is allowed or not *within* the module is 
orthogonal to `closed`.  *Outside* the module it would only be possible for 
enum declared `open` (if we add this feature in the future).


public func bar(b: B) {
switch b {
case .b:
print("b")

default: // always needed
print("some other case")
}
}

// Sub-enum relationships

// Possible even the enum A is closed, because `@closed` only   
// closes the extensibility of an enum
enum SubA : A {
case aa
}

Now you're talking about value subtypes.  That is orthogonal.  Also, this 
syntax already has a meaning (the raw value of the enum is A) so we wouldn't be 
able to use it the way you are intending here.  Finally, it is misleading 
syntax because what you mean here is "A is a subtype of SubA" which is exactly 
the opposite of what the syntax implies.

All values of A are valid values of SubA, but SubA has values that are not 
valid values of A.

// The following enum can have a sub-enum in the clients module
open enum C {
case c
}
public func cool(c: C) {
switch c {
case .c:
print("c")

default: // always needed
print("some other case")
}
}

@closed open enum D {
case d
}

public func doo(d: D) {
switch b {
case .b:
print("b")
}
}

// The enum case is always known at any point, no matter   
// where the instance comes from, right?

let subA = SubA.aa
let otherSubA = SubA.a // Inherited case

let a: A = subA// error, downgrade the sub-enum to A first
let a: A = otherSubA   // okay

foo(a: subA)   // error, downgrade the sub-enum to A first
foo(a: otherSubA)  // okay

//===- Module B -===//

// Totally fine   
switch A.a {
case .a:
print("done")
}

extension A {
case aa // not allowed because the enum is closed
}

extension B {
case bbb
}

switch B.b {
case .b:
print("b")
default:   
print("somethine else")
}

bar(b: B.bbb) // fine, because the switch statement on enums without   
// `@closed` has always`default`

// Allowed because `C` is open, and open allows sub-typing, conforming   
// and overriding to the client
enum SubC : C {
case cc
}

let subC = SubC.cc

cool(c: subC) // okay

enum SubD : D {
case dd
}

doo(d: D.dd)// error, downgrade sub-enum to D first

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-11 Thread Karl Wagner via swift-evolution

> On 11 Feb 2017, at 14:37, Karl Wagner  wrote:
> 
> 
>> On 9 Feb 2017, at 00:05, Matthew Johnson via swift-evolution 
>> > wrote:
>> 
>> I’ve been thinking a lot about our public access modifier story lately in 
>> the context of both protocols and enums.  I believe we should move further 
>> in the direction we took when introducing the `open` keyword.  I have 
>> identified what I think is a promising direction and am interested in 
>> feedback from the community.  If community feedback is positive I will flesh 
>> this out into a more complete proposal draft.
>> 
>> 
>> Background and Motivation:
>> 
>> In Swift 3 we had an extended debate regarding whether or not to allow 
>> inheritance of public classes by default or to require an annotation for 
>> classes that could be subclassed outside the module.  The decision we 
>> reached was to avoid having a default at all, and instead make `open` an 
>> access modifier.  The result is library authors are required to consider the 
>> behavior they wish for each class.  Both behaviors are equally convenient 
>> (neither is penalized by requiring an additional boilerplate-y annotation).
>> 
>> A recent thread 
>> (https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170206/031566.html
>>  
>> )
>>  discussed a similar tradeoff regarding whether public enums should commit 
>> to a fixed set of cases by default or not.  The current behavior is that 
>> they *do* commit to a fixed set of cases and there is no option (afaik) to 
>> modify that behavior.  The Library Evolution document 
>> (https://github.com/apple/swift/blob/master/docs/LibraryEvolution.rst#enums 
>> )
>>  suggests a desire to change this before locking down ABI such that public 
>> enums *do not* make this commitment by default, and are required to opt-in 
>> to this behavior using an `@closed` annotation.
>> 
>> In the previous discussion I stated a strong preference that closed enums 
>> *not* be penalized with an additional annotation.  This is because I feel 
>> pretty strongly that it is a design smell to: 1) expose cases publicly if 
>> consumers of the API are not expected to switch on them and 2) require users 
>> to handle unknown future cases if they are likely to switch over the cases 
>> in correct use of the API.
>> 
>> The conclusion I came to in that thread is that we should adopt the same 
>> strategy as we did with classes: there should not be a default.
>> 
>> There have also been several discussions both on the list and via Twitter 
>> regarding whether or not we should allow closed protocols.  In a recent 
>> Twitter discussion Joe Groff suggested that we don’t need them because we 
>> should use an enum when there is a fixed set of conforming types.  There are 
>> at least two  reasons why I still think we *should* add support for closed 
>> protocols.
>> 
>> As noted above (and in the previous thread in more detail), if the set of 
>> types (cases) isn’t intended to be fixed (i.e. the library may add new types 
>> in the future) an enum is likely not a good choice.  Using a closed protocol 
>> discourages the user from switching and prevents the user from adding 
>> conformances that are not desired.
>> 
>> Another use case supported by closed protocols is a design where users are 
>> not allowed to conform directly to a protocol, but instead are required to 
>> conform to one of several protocols which refine the closed protocol.  Enums 
>> are not a substitute for this use case.  The only option is to resort to 
>> documentation and runtime checks.
>> 
>> 
>> Proposal:
>> 
>> This proposal introduces the new access modifier `closed` as well as 
>> clarifying the meaning of `public` and expanding the use of `open`.  This 
>> provides consistent capabilities and semantics across enums, classes and 
>> protocols.
>> 
>> `open` is the most permissive modifier.  The symbol is visible outside the 
>> module and both users and future versions of the library are allowed to add 
>> new cases, subclasses or conformances.  (Note: this proposal does not 
>> introduce user-extensible `open` enums, but provides the syntax that would 
>> be used if they are added to the language)
>> 
>> `public` makes the symbol visible without allowing the user to add new 
>> cases, subclasses or conformances.  The library reserves the right to add 
>> new cases, subclasses or conformances in a future version.
>> 
>> `closed` is the most restrictive modifier.  The symbol is visible publicly 
>> with the commitment that future versions of the library are *also* 
>> prohibited from adding new cases, subclasses or conformances.  Additionally, 
>> all cases, subclasses or conformances must be visible outside the module.
>> 
>> Note: the `closed` 

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-11 Thread Karl Wagner via swift-evolution

> On 9 Feb 2017, at 00:05, Matthew Johnson via swift-evolution 
>  wrote:
> 
> I’ve been thinking a lot about our public access modifier story lately in the 
> context of both protocols and enums.  I believe we should move further in the 
> direction we took when introducing the `open` keyword.  I have identified 
> what I think is a promising direction and am interested in feedback from the 
> community.  If community feedback is positive I will flesh this out into a 
> more complete proposal draft.
> 
> 
> Background and Motivation:
> 
> In Swift 3 we had an extended debate regarding whether or not to allow 
> inheritance of public classes by default or to require an annotation for 
> classes that could be subclassed outside the module.  The decision we reached 
> was to avoid having a default at all, and instead make `open` an access 
> modifier.  The result is library authors are required to consider the 
> behavior they wish for each class.  Both behaviors are equally convenient 
> (neither is penalized by requiring an additional boilerplate-y annotation).
> 
> A recent thread 
> (https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170206/031566.html
>  
> )
>  discussed a similar tradeoff regarding whether public enums should commit to 
> a fixed set of cases by default or not.  The current behavior is that they 
> *do* commit to a fixed set of cases and there is no option (afaik) to modify 
> that behavior.  The Library Evolution document 
> (https://github.com/apple/swift/blob/master/docs/LibraryEvolution.rst#enums 
> ) 
> suggests a desire to change this before locking down ABI such that public 
> enums *do not* make this commitment by default, and are required to opt-in to 
> this behavior using an `@closed` annotation.
> 
> In the previous discussion I stated a strong preference that closed enums 
> *not* be penalized with an additional annotation.  This is because I feel 
> pretty strongly that it is a design smell to: 1) expose cases publicly if 
> consumers of the API are not expected to switch on them and 2) require users 
> to handle unknown future cases if they are likely to switch over the cases in 
> correct use of the API.
> 
> The conclusion I came to in that thread is that we should adopt the same 
> strategy as we did with classes: there should not be a default.
> 
> There have also been several discussions both on the list and via Twitter 
> regarding whether or not we should allow closed protocols.  In a recent 
> Twitter discussion Joe Groff suggested that we don’t need them because we 
> should use an enum when there is a fixed set of conforming types.  There are 
> at least two  reasons why I still think we *should* add support for closed 
> protocols.
> 
> As noted above (and in the previous thread in more detail), if the set of 
> types (cases) isn’t intended to be fixed (i.e. the library may add new types 
> in the future) an enum is likely not a good choice.  Using a closed protocol 
> discourages the user from switching and prevents the user from adding 
> conformances that are not desired.
> 
> Another use case supported by closed protocols is a design where users are 
> not allowed to conform directly to a protocol, but instead are required to 
> conform to one of several protocols which refine the closed protocol.  Enums 
> are not a substitute for this use case.  The only option is to resort to 
> documentation and runtime checks.
> 
> 
> Proposal:
> 
> This proposal introduces the new access modifier `closed` as well as 
> clarifying the meaning of `public` and expanding the use of `open`.  This 
> provides consistent capabilities and semantics across enums, classes and 
> protocols.
> 
> `open` is the most permissive modifier.  The symbol is visible outside the 
> module and both users and future versions of the library are allowed to add 
> new cases, subclasses or conformances.  (Note: this proposal does not 
> introduce user-extensible `open` enums, but provides the syntax that would be 
> used if they are added to the language)
> 
> `public` makes the symbol visible without allowing the user to add new cases, 
> subclasses or conformances.  The library reserves the right to add new cases, 
> subclasses or conformances in a future version.
> 
> `closed` is the most restrictive modifier.  The symbol is visible publicly 
> with the commitment that future versions of the library are *also* prohibited 
> from adding new cases, subclasses or conformances.  Additionally, all cases, 
> subclasses or conformances must be visible outside the module.
> 
> Note: the `closed` modifier only applies to *direct* subclasses or 
> conformances.  A subclass of a `closed` class need not be `closed`, in fact 
> it may be `open` if the design of the library requires that.  A class that 
> 

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-11 Thread Rien via swift-evolution
I admit that I have not followed all of this discussion, but as far as I see, 
we could equally well do this by calling “not-open” enum’s “final”.
It seems like a better fit to me.

Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: http://github.com/Balancingrock
Project: http://swiftfire.nl





> On 11 Feb 2017, at 14:07, Matthew Johnson via swift-evolution 
>  wrote:
> 
> 
> 
> Sent from my iPad
> 
> On Feb 11, 2017, at 4:25 AM, Adrian Zubarev via swift-evolution 
>  wrote:
> 
>> I’m probably better describing things with some bikeshedding code, but feel 
>> free to criticize it as much as you’d like.
>> 
>> //===- Module A -===//
>> @closed public enum A {
>> case a
>> }
>> 
>> extension A {
>> case aa // error, because enum is closed
>> }
>> 
> This is an error because you can't add cases in an extension.  I imagine this 
> is how cases would be added outside the module if we allow `open enum` in the 
> future.  But whether or not this is allowed *within* the module is a separate 
> question that is orthogonal to `closed` and `open`.
> 
> 
>> 
>> public func foo(a: A) {
>> switch a {
>> case .a:
>> print("done")
>> }
>> }
>> 
>> public enum B {
>> case b
>> }
>> 
>> extension B {
>> case bb // fine, because not-closed enums are extensible
>> }
>> 
> As noted above, whether this is allowed or not *within* the module is 
> orthogonal to `closed`.  *Outside* the module it would only be possible for 
> enum declared `open` (if we add this feature in the future).
> 
>> 
>> public func bar(b: B) {
>> switch b {
>> case .b:
>> print("b")
>> 
>> default: // always needed
>> print("some other case")
>> }
>> }
>> 
>> // Sub-enum relationships
>> 
>> // Possible even the enum A is closed, because `@closed` only  
>> // closes the extensibility of an enum
>> enum SubA : A {
>> case aa
>> }
>> 
>> 
> Now you're talking about value subtypes.  That is orthogonal.  Also, this 
> syntax already has a meaning (the raw value of the enum is A) so we wouldn't 
> be able to use it the way you are intending here.  Finally, it is misleading 
> syntax because what you mean here is "A is a subtype of SubA" which is 
> exactly the opposite of what the syntax implies.
> 
> All values of A are valid values of SubA, but SubA has values that are not 
> valid values of A.
> 
>> // The following enum can have a sub-enum in the clients module
>> open enum C {
>> case c
>> }
>> 
>> public func cool(c: C) {
>> switch c {
>> case .c:
>> print("c")
>> 
>> default: // always needed
>> print("some other case")
>> }
>> }
>> 
>> @closed open enum D {
>> case d
>> }
>> 
>> public func doo(d: D) {
>> switch b {
>> case .b:
>> print("b")
>> }
>> }
>> 
>> // The enum case is always known at any point, no matter  
>> // where the instance comes from, right?
>> 
>> let subA = SubA.aa
>> let otherSubA = SubA.a // Inherited case
>> 
>> let a: A = subA// error, downgrade the sub-enum to A first
>> let a: A = otherSubA   // okay
>> 
>> foo(a: subA)   // error, downgrade the sub-enum to A first
>> foo(a: otherSubA)  // okay
>> 
>> //===- Module B -===//
>> 
>> // Totally fine  
>> switch A.a {
>> case .a:
>> print("done")
>> }
>> 
>> extension A {
>> case aa // not allowed because the enum is closed
>> }
>> 
>> extension B {
>> case bbb
>> }
>> 
>> switch B.b {
>> case .b:
>> print("b")
>> default:  
>> print("somethine else")
>> }
>> 
>> bar(b: B.bbb) // fine, because the switch statement on enums without  
>> // `@closed` has always`default`
>> 
>> // Allowed because `C` is open, and open allows sub-typing, conforming  
>> // and overriding to the client
>> enum SubC : C {
>> case cc
>> }
>> 
>> let subC = 
>> SubC.cc
>> 
>> 
>> cool(c: subC) // okay
>> 
>> enum SubD : D {
>> case dd
>> }
>> 
>> doo(d: D.dd)// error, downgrade sub-enum to D first
>> 
>> My point here is, that we should not think of (possible) open enums as enums 
>> that the client is allowed to extend. That way we’re only creating another 
>> inconsistent case for the open access modifier. As far as I can tell, open 
>> as for today means “the client is allowed to subclass/override things from a 
>> different module”. 
>> 
> Yes, but subclasses are analogous to enum cases.  A subtype of an enum would 
> remove cases.  I think you are misunderstanding the relationship of enums to 
> classes and protocols.
> 
>> And I already said it hundred of times that we should extend this to make 
>> open a true access modifier in Swift. That said the meaning of open should 
>> become:
>> 
>>  • The client is allowed to sub-type (currently only classes are 
>> supported).
>>  • The client is allowed to conform to open protocols
>>  • The client is 

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-11 Thread Matthew Johnson via swift-evolution


Sent from my iPad

> On Feb 11, 2017, at 4:25 AM, Adrian Zubarev via swift-evolution 
>  wrote:
> 
> I’m probably better describing things with some bikeshedding code, but feel 
> free to criticize it as much as you’d like.
> 
> //===- Module A -===//
> @closed public enum A {
> case a
> }
> 
> extension A {
> case aa // error, because enum is closed
> }
This is an error because you can't add cases in an extension.  I imagine this 
is how cases would be added outside the module if we allow `open enum` in the 
future.  But whether or not this is allowed *within* the module is a separate 
question that is orthogonal to `closed` and `open`.


> 
> public func foo(a: A) {
> switch a {
> case .a:
> print("done")
> }
> }
> 
> public enum B {
> case b
> }
> 
> extension B {
> case bb // fine, because not-closed enums are extensible
> }
As noted above, whether this is allowed or not *within* the module is 
orthogonal to `closed`.  *Outside* the module it would only be possible for 
enum declared `open` (if we add this feature in the future).

> 
> public func bar(b: B) {
> switch b {
> case .b:
> print("b")
> 
> default: // always needed
> print("some other case")
> }
> }
> 
> // Sub-enum relationships
> 
> // Possible even the enum A is closed, because `@closed` only  
> // closes the extensibility of an enum
> enum SubA : A {
> case aa
> }
> 
Now you're talking about value subtypes.  That is orthogonal.  Also, this 
syntax already has a meaning (the raw value of the enum is A) so we wouldn't be 
able to use it the way you are intending here.  Finally, it is misleading 
syntax because what you mean here is "A is a subtype of SubA" which is exactly 
the opposite of what the syntax implies.

All values of A are valid values of SubA, but SubA has values that are not 
valid values of A.

> // The following enum can have a sub-enum in the clients module
> open enum C {
> case c
> }
> public func cool(c: C) {
> switch c {
> case .c:
> print("c")
> 
> default: // always needed
> print("some other case")
> }
> }
> 
> @closed open enum D {
> case d
> }
> 
> public func doo(d: D) {
> switch b {
> case .b:
> print("b")
> }
> }
> 
> // The enum case is always known at any point, no matter  
> // where the instance comes from, right?
> 
> let subA = SubA.aa
> let otherSubA = SubA.a // Inherited case
> 
> let a: A = subA// error, downgrade the sub-enum to A first
> let a: A = otherSubA   // okay
> 
> foo(a: subA)   // error, downgrade the sub-enum to A first
> foo(a: otherSubA)  // okay
> 
> //===- Module B -===//
> 
> // Totally fine  
> switch A.a {
> case .a:
> print("done")
> }
> 
> extension A {
> case aa // not allowed because the enum is closed
> }
> 
> extension B {
> case bbb
> }
> 
> switch B.b {
> case .b:
> print("b")
> default:  
> print("somethine else")
> }
> 
> bar(b: B.bbb) // fine, because the switch statement on enums without  
> // `@closed` has always`default`
> 
> // Allowed because `C` is open, and open allows sub-typing, conforming  
> // and overriding to the client
> enum SubC : C {
> case cc
> }
> 
> let subC = SubC.cc
> 
> cool(c: subC) // okay
> 
> enum SubD : D {
> case dd
> }
> 
> doo(d: D.dd)// error, downgrade sub-enum to D first
> My point here is, that we should not think of (possible) open enums as enums 
> that the client is allowed to extend. That way we’re only creating another 
> inconsistent case for the open access modifier. As far as I can tell, open as 
> for today means “the client is allowed to subclass/override things from a 
> different module”.
> 
Yes, but subclasses are analogous to enum cases.  A subtype of an enum would 
remove cases.  I think you are misunderstanding the relationship of enums to 
classes and protocols.

> And I already said it hundred of times that we should extend this to make 
> open a true access modifier in Swift. That said the meaning of open should 
> become:
> 
> The client is allowed to sub-type (currently only classes are supported).
> The client is allowed to conform to open protocols
> The client is allowed to override open type members
> This also means that extensibility is still allowed to public types. 
> Public-but-not-open classes are still extensible today, which is the correct 
> behavior. Extending an enum which is not closed could or probably should be 
> made possible through extensions, because I cannot think of anther elegant 
> way for the client to do so.
> 
This is what `open enum` would allow.  It is the proper enum analogue of open 
classes.

> That will leave us the possibility to think of sub-typing enums in the future 
> (I sketched it out a little above).
> 
Value subtyping is very interesting.  I have been working on some ideas around 
this but I want to 

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-11 Thread Matthew Johnson via swift-evolution


Sent from my iPad

> On Feb 10, 2017, at 9:48 PM, Xiaodi Wu  wrote:
> 
>> On Wed, Feb 8, 2017 at 5:05 PM, Matthew Johnson via swift-evolution 
>>  wrote:
>> I’ve been thinking a lot about our public access modifier story lately in 
>> the context of both protocols and enums.  I believe we should move further 
>> in the direction we took when introducing the `open` keyword.  I have 
>> identified what I think is a promising direction and am interested in 
>> feedback from the community.  If community feedback is positive I will flesh 
>> this out into a more complete proposal draft.
>> 
>> 
>> Background and Motivation:
>> 
>> In Swift 3 we had an extended debate regarding whether or not to allow 
>> inheritance of public classes by default or to require an annotation for 
>> classes that could be subclassed outside the module.  The decision we 
>> reached was to avoid having a default at all, and instead make `open` an 
>> access modifier.  The result is library authors are required to consider the 
>> behavior they wish for each class.  Both behaviors are equally convenient 
>> (neither is penalized by requiring an additional boilerplate-y annotation).
>> 
>> A recent thread 
>> (https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170206/031566.html)
>>  discussed a similar tradeoff regarding whether public enums should commit 
>> to a fixed set of cases by default or not.  The current behavior is that 
>> they *do* commit to a fixed set of cases and there is no option (afaik) to 
>> modify that behavior.  The Library Evolution document 
>> (https://github.com/apple/swift/blob/master/docs/LibraryEvolution.rst#enums) 
>> suggests a desire to change this before locking down ABI such that public 
>> enums *do not* make this commitment by default, and are required to opt-in 
>> to this behavior using an `@closed` annotation.
>> 
>> In the previous discussion I stated a strong preference that closed enums 
>> *not* be penalized with an additional annotation.  This is because I feel 
>> pretty strongly that it is a design smell to: 1) expose cases publicly if 
>> consumers of the API are not expected to switch on them and 2) require users 
>> to handle unknown future cases if they are likely to switch over the cases 
>> in correct use of the API.
>> 
>> The conclusion I came to in that thread is that we should adopt the same 
>> strategy as we did with classes: there should not be a default.
>> 
>> There have also been several discussions both on the list and via Twitter 
>> regarding whether or not we should allow closed protocols.  In a recent 
>> Twitter discussion Joe Groff suggested that we don’t need them because we 
>> should use an enum when there is a fixed set of conforming types.  There are 
>> at least two  reasons why I still think we *should* add support for closed 
>> protocols.
>> 
>> As noted above (and in the previous thread in more detail), if the set of 
>> types (cases) isn’t intended to be fixed (i.e. the library may add new types 
>> in the future) an enum is likely not a good choice.  Using a closed protocol 
>> discourages the user from switching and prevents the user from adding 
>> conformances that are not desired.
>> 
>> Another use case supported by closed protocols is a design where users are 
>> not allowed to conform directly to a protocol, but instead are required to 
>> conform to one of several protocols which refine the closed protocol.  Enums 
>> are not a substitute for this use case.  The only option is to resort to 
>> documentation and runtime checks.
>> 
>> 
>> Proposal:
>> 
>> This proposal introduces the new access modifier `closed` as well as 
>> clarifying the meaning of `public` and expanding the use of `open`.  This 
>> provides consistent capabilities and semantics across enums, classes and 
>> protocols.
>> 
>> `open` is the most permissive modifier.  The symbol is visible outside the 
>> module and both users and future versions of the library are allowed to add 
>> new cases, subclasses or conformances.  (Note: this proposal does not 
>> introduce user-extensible `open` enums, but provides the syntax that would 
>> be used if they are added to the language)
>> 
>> `public` makes the symbol visible without allowing the user to add new 
>> cases, subclasses or conformances.  The library reserves the right to add 
>> new cases, subclasses or conformances in a future version.
>> 
>> `closed` is the most restrictive modifier.  The symbol is visible publicly 
>> with the commitment that future versions of the library are *also* 
>> prohibited from adding new cases, subclasses or conformances.  Additionally, 
>> all cases, subclasses or conformances must be visible outside the module.
>> 
>> Note: the `closed` modifier only applies to *direct* subclasses or 
>> conformances.  A subclass of a `closed` class need not be `closed`, in fact 
>> it may be `open` if the design of the library requires that.  A 

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-11 Thread Matthew Johnson via swift-evolution


Sent from my iPad

> On Feb 10, 2017, at 9:35 PM, Xiaodi Wu  wrote:
> 
>> On Fri, Feb 10, 2017 at 9:15 AM, Matthew Johnson  
>> wrote:
>> 
>>> On Feb 10, 2017, at 1:06 AM, Xiaodi Wu  wrote:
>>> 
 On Thu, Feb 9, 2017 at 9:57 AM, Matthew Johnson  
 wrote:
 
> On Feb 8, 2017, at 5:48 PM, Xiaodi Wu  wrote:
> 
> I agree very much with rationalizing access levels, but I'm not sure I 
> like this proposal for public vs. closed. How would the compiler stop me 
> from editing my own code if something is closed? The answer must be that 
> it can't, so I can't see it as a co-equal to open but rather simply a 
> statement of intention. Therefore I think use cases for the proposed 
> behavior of closed would be better served by annotations and proper 
> semantic versioning.
 
 The most important point IMO is that they *are* co-equal in the sense that 
 they define a contract between library authors, library users and the 
 compiler.
>>> 
>>> Certainly, `open` and your proposed `closed` both represent contracts among 
>>> library authors, users, and the compiler. But so do other features that are 
>>> not access modifiers--unless your intent is to make all the (not yet 
>>> totally finalized) resilience attributes such as `@inlineable` become 
>>> access modifiers. That both `open` and the proposed `closed` are both 
>>> contracts doesn't make them both access modifiers.
>> 
>> This is a good point.  But `open`, `closed` and `public` have something very 
>> important in common: they all have meaning with regarding the set of cases, 
>> subclasses or conforming types and are mutually exclusive in the contract 
>> they offer in this regard.
>> 
>>> 
>>> To me, the reason one _could_ justify `open` being spelled like an access 
>>> modifier (which I was not supportive of, actually, though I was fine with 
>>> `public` not allowing subclassing) is that it quacks like an access 
>>> modifier in some ways. In particular, since it offers more "access" to a 
>>> class than does `public` by allowing subclassing, one can argue that it 
>>> fits at the top of a hierarchy of access levels.
>>> 
>>> As you define it, `closed` also makes additional guarantees to the end user 
>>> than does `public` by (self-)imposing restrictions on the library author. 
>>> Thus, it does not fit into a hierarchy of access modifiers where each level 
>>> is more "accessible" than the next. Put another way, my point here is that 
>>> `closed` is not the opposite of `open` in key ways, as the names might 
>>> suggest. In fact, from the perspective of a library user, both `closed` and 
>>> `open` would allow you to do more than `public`.
>> 
>> You make a great point here when you say that `closed` makes additional 
>> guarantees to the end user, beyond `public`.  `closed` and `open` both give 
>> users more capabilities by placing additional burden on the library.  In a 
>> very real sense `closed` *does* provide more visibility to information about 
>> the type - it guarantees knowledge of the *complete* set of cases, 
>> subclasses or protocols both now and in the future (modulo breaking 
>> changes).  In this sense it can be said to be “more accessible than public”. 
>>  This does form a strict hierarchy, just not a linear one:
>> 
>> private
>>   |
>>   fileprivate
>>   |
>> internal
>>   |
>>  public
>> / \
>> closed  open
> 
> Yes, I think we are now on the same page as to the mental model here. As to 
> whether a non-linear hierarchy is desirable or not, that's a judgment call.

Great!  

Of course, everything in language design is ultimately a judgement call.  My 
opinion is that a non-linear hierarchy turns out to be a natural consequence of 
the decision we made regarding `open`.  Adopting this approach has a compelling 
and consistent logic that other approaches won't have as long as `open` is an 
access modifier.

I think this is a good thing - it means the language doesn't syntactically 
favor or penalize any of `public`, `open` and `closed`.  Instead it requires an 
explicit choice between them and gives them equal syntactic weight.

A reasonable case can be made that `open` and `closed` shouldn't be access 
modifiers.  But I feel like that ship sailed when `open` was introduced.  

Personally, I feel like we made the best trade off possible and the same logic 
is relevant to the `closed` discussion.  

Most importantly, I think we should strive for consistency.  It is currently 
lacking and would get worse if `@closed` were introduced as an attribute.

>  
>> I admit that the name `closed` doesn’t *sounds* more accessible.  Maybe 
>> there is a better name?  But `closed` is the name we have all been using for 
>> this contract and it offers a 

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-11 Thread Adrian Zubarev via swift-evolution
I’m probably better describing things with some bikeshedding code, but feel 
free to criticize it as much as you’d like.

//===- Module A -===//
@closed public enum A {
case a
}

extension A {
case aa // error, because enum is closed
}

public func foo(a: A) {
switch a {
case .a:
print("done")
}
}

public enum B {
case b
}

extension B {
case bb // fine, because not-closed enums are extensible
}

public func bar(b: B) {
switch b {
case .b:
print("b")

default: // always needed
print("some other case")
}
}

// Sub-enum relationships

// Possible even the enum A is closed, because `@closed` only  
// closes the extensibility of an enum
enum SubA : A {
case aa
}

// The following enum can have a sub-enum in the clients module
open enum C {
case c
}

public func cool(c: C) {
switch c {
case .c:
print("c")

default: // always needed
print("some other case")
}
}

@closed open enum D {
case d
}

public func doo(d: D) {
switch b {
case .b:
print("b")
}
}

// The enum case is always known at any point, no matter  
// where the instance comes from, right?

let subA = SubA.aa
let otherSubA = SubA.a // Inherited case

let a: A = subA// error, downgrade the sub-enum to A first
let a: A = otherSubA   // okay

foo(a: subA)   // error, downgrade the sub-enum to A first
foo(a: otherSubA)  // okay

//===- Module B -===//

// Totally fine  
switch A.a {
case .a:
print("done")
}

extension A {
case aa // not allowed because the enum is closed
}

extension B {
case bbb
}

switch B.b {
case .b:
print("b")
default:  
print("somethine else")
}

bar(b: B.bbb) // fine, because the switch statement on enums without  
// `@closed` has always`default`

// Allowed because `C` is open, and open allows sub-typing, conforming  
// and overriding to the client
enum SubC : C {
case cc
}

let subC = SubC.cc

cool(c: subC) // okay

enum SubD : D {
case dd
}

doo(d: D.dd)// error, downgrade sub-enum to D first
My point here is, that we should not think of (possible) open enums as enums 
that the client is allowed to extend. That way we’re only creating another 
inconsistent case for the open access modifier. As far as I can tell, open as 
for today means “the client is allowed to subclass/override things from a 
different module”. And I already said it hundred of times that we should extend 
this to make open a true access modifier in Swift. That said the meaning of 
open should become:

The client is allowed to sub-type (currently only classes are supported).
The client is allowed to conform to open protocols
The client is allowed to override open type members
This also means that extensibility is still allowed to public types. 
Public-but-not-open classes are still extensible today, which is the correct 
behavior. Extending an enum which is not closed could or probably should be 
made possible through extensions, because I cannot think of anther elegant way 
for the client to do so. That will leave us the possibility to think of 
sub-typing enums in the future (I sketched it out a little above). If I’m not 
mistaken, every enum case is known at compile time, which means to me that we 
can safely check the case before allowing to assign or pass an instance of a 
sub-enum to some of its super-enum. (Downgrading an enum case means that you 
will have to write some code that either mutates your current instance or 
creates a new one which matches one of the super-enum cases.) Furthermore that 
allows a clear distinction of what open access modifier does and how @closed 
behaves.

To summarize:

@closed enum - you’re not allowed to add new cases to the enum in your lib + 
(you’re allowed to create sub-enums)
@closed public enum - you and the client are not allowed to add new cases (+ 
the client is not allowed to create sub-enums)
@closed open enum - you and the client are not allowed to add new cases (+ the 
client might create new sub-enums)
enum - you’re allowed to add new cases (default is needed in switch statements) 
(+ you can create new sub-enums)
public enum - you and the client are allowed to add new cases (+ only you are 
allowed to create new sub-enums)
open enum - you and the client are allowed to add new cases (everyone can 
create new sub-enums)
This is a lot of bike shedding of mine, and the idea might not even see any 
light in Swift at all, but I’d like to share my ideas with the community. Feel 
free to criticize them or flesh something out into something real. :)

P.S.: If we had something like this:

@closed enum X {
case x, y
func foo() {
 switch self {
case .x, .y:
print("swift")
}
}

enum Z : X {
case z, zz
override func foo() {
// Iff `self` is `z` or `zz` then calling super will result in an error.
// Possible solution: 

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-10 Thread Xiaodi Wu via swift-evolution
On Wed, Feb 8, 2017 at 5:05 PM, Matthew Johnson via swift-evolution <
swift-evolution@swift.org> wrote:

> I’ve been thinking a lot about our public access modifier story lately in
> the context of both protocols and enums.  I believe we should move further
> in the direction we took when introducing the `open` keyword.  I have
> identified what I think is a promising direction and am interested in
> feedback from the community.  If community feedback is positive I will
> flesh this out into a more complete proposal draft.
>
>
> Background and Motivation:
>
> In Swift 3 we had an extended debate regarding whether or not to allow
> inheritance of public classes by default or to require an annotation for
> classes that could be subclassed outside the module.  The decision we
> reached was to avoid having a default at all, and instead make `open` an
> access modifier.  The result is library authors are required to consider
> the behavior they wish for each class.  Both behaviors are equally
> convenient (neither is penalized by requiring an additional boilerplate-y
> annotation).
>
> A recent thread (https://lists.swift.org/piper
> mail/swift-evolution/Week-of-Mon-20170206/031566.html) discussed a
> similar tradeoff regarding whether public enums should commit to a fixed
> set of cases by default or not.  The current behavior is that they *do*
> commit to a fixed set of cases and there is no option (afaik) to modify
> that behavior.  The Library Evolution document (
> https://github.com/apple/swift/blob/master/docs/LibraryEvolution.rst#enums)
> suggests a desire to change this before locking down ABI such that public
> enums *do not* make this commitment by default, and are required to opt-in
> to this behavior using an `@closed` annotation.
>
> In the previous discussion I stated a strong preference that closed enums
> *not* be penalized with an additional annotation.  This is because I feel
> pretty strongly that it is a design smell to: 1) expose cases publicly if
> consumers of the API are not expected to switch on them and 2) require
> users to handle unknown future cases if they are likely to switch over the
> cases in correct use of the API.
>
> The conclusion I came to in that thread is that we should adopt the same
> strategy as we did with classes: there should not be a default.
>
> There have also been several discussions both on the list and via Twitter
> regarding whether or not we should allow closed protocols.  In a recent
> Twitter discussion Joe Groff suggested that we don’t need them because we
> should use an enum when there is a fixed set of conforming types.  There
> are at least two  reasons why I still think we *should* add support for
> closed protocols.
>
> As noted above (and in the previous thread in more detail), if the set of
> types (cases) isn’t intended to be fixed (i.e. the library may add new
> types in the future) an enum is likely not a good choice.  Using a closed
> protocol discourages the user from switching and prevents the user from
> adding conformances that are not desired.
>
> Another use case supported by closed protocols is a design where users are
> not allowed to conform directly to a protocol, but instead are required to
> conform to one of several protocols which refine the closed protocol.
> Enums are not a substitute for this use case.  The only option is to resort
> to documentation and runtime checks.
>
>
> Proposal:
>
> This proposal introduces the new access modifier `closed` as well as
> clarifying the meaning of `public` and expanding the use of `open`.  This
> provides consistent capabilities and semantics across enums, classes and
> protocols.
>
> `open` is the most permissive modifier.  The symbol is visible outside the
> module and both users and future versions of the library are allowed to add
> new cases, subclasses or conformances.  (Note: this proposal does not
> introduce user-extensible `open` enums, but provides the syntax that would
> be used if they are added to the language)
>
> `public` makes the symbol visible without allowing the user to add new
> cases, subclasses or conformances.  The library reserves the right to add
> new cases, subclasses or conformances in a future version.
>
> `closed` is the most restrictive modifier.  The symbol is visible publicly
> with the commitment that future versions of the library are *also*
> prohibited from adding new cases, subclasses or conformances.
> Additionally, all cases, subclasses or conformances must be visible outside
> the module.
>
> Note: the `closed` modifier only applies to *direct* subclasses or
> conformances.  A subclass of a `closed` class need not be `closed`, in fact
> it may be `open` if the design of the library requires that.  A class that
> conforms to a `closed` protocol also need not be `closed`.  It may also be
> `open`.  Finally, a protocol that refines a `closed` protocol need not be
> `closed`.  It may also be `open`.
>
> This proposal is consistent with the 

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-10 Thread Xiaodi Wu via swift-evolution
On Fri, Feb 10, 2017 at 9:15 AM, Matthew Johnson 
wrote:

>
> On Feb 10, 2017, at 1:06 AM, Xiaodi Wu  wrote:
>
> On Thu, Feb 9, 2017 at 9:57 AM, Matthew Johnson 
> wrote:
>
>>
>> On Feb 8, 2017, at 5:48 PM, Xiaodi Wu  wrote:
>>
>> I agree very much with rationalizing access levels, but I'm not sure I
>> like this proposal for public vs. closed. How would the compiler stop me
>> from editing my own code if something is closed? The answer must be that it
>> can't, so I can't see it as a co-equal to open but rather simply a
>> statement of intention. Therefore I think use cases for the proposed
>> behavior of closed would be better served by annotations and proper
>> semantic versioning.
>>
>>
>> The most important point IMO is that they *are* co-equal in the sense
>> that they define a contract between library authors, library users and the
>> compiler.
>>
>
> Certainly, `open` and your proposed `closed` both represent contracts
> among library authors, users, and the compiler. But so do other features
> that are not access modifiers--unless your intent is to make all the (not
> yet totally finalized) resilience attributes such as `@inlineable` become
> access modifiers. That both `open` and the proposed `closed` are both
> contracts doesn't make them both access modifiers.
>
>
> This is a good point.  But `open`, `closed` and `public` have something
> very important in common: they all have meaning with regarding the set of
> cases, subclasses or conforming types and are mutually exclusive in the
> contract they offer in this regard.
>
>
> To me, the reason one _could_ justify `open` being spelled like an access
> modifier (which I was not supportive of, actually, though I was fine with
> `public` not allowing subclassing) is that it quacks like an access
> modifier in some ways. In particular, since it offers more "access" to a
> class than does `public` by allowing subclassing, one can argue that it
> fits at the top of a hierarchy of access levels.
>
> As you define it, `closed` also makes additional guarantees to the end
> user than does `public` by (self-)imposing restrictions on the library
> author. Thus, it does not fit into a hierarchy of access modifiers where
> each level is more "accessible" than the next. Put another way, my point
> here is that `closed` is not the opposite of `open` in key ways, as the
> names might suggest. In fact, from the perspective of a library user, both
> `closed` and `open` would allow you to do more than `public`.
>
>
> You make a great point here when you say that `closed` makes additional
> guarantees to the end user, beyond `public`.  `closed` and `open` both give
> users more capabilities by placing additional burden on the library.  In a
> very real sense `closed` *does* provide more visibility to information
> about the type - it guarantees knowledge of the *complete* set of cases,
> subclasses or protocols both now and in the future (modulo breaking
> changes).  In this sense it can be said to be “more accessible than
> public”.  This does form a strict hierarchy, just not a linear one:
>
> private
>   |
>   fileprivate
>   |
> internal
>   |
>  public
> / \
> closed  open
>

Yes, I think we are now on the same page as to the mental model here. As to
whether a non-linear hierarchy is desirable or not, that's a judgment call.


> I admit that the name `closed` doesn’t *sounds* more accessible.  Maybe
> there is a better name?  But `closed` is the name we have all been using
> for this contract and it offers a nice symmetry with open.  One opens the
> set of cases, subclasses, or conforming types to users.  The other closes
> off the ability of the library to add to or hide any members of the set of
> cases, subclasses or conforming types.  The symmetry is in the fact that
> they both say something about the totality of the set of cases, subclasses
> or conforming types.
>
> It’s also worth noting that a `public` type can become `closed` or `open`
> in a future version of a library, but once `closed` or `open` that option
> is fixed forever (modulo breaking changes).  This also suggests the
> hierarchy I visualized above.
>
>
> As you note, there are some differences in how the `closed` contract is
>> supported.  But that is far less important than the meaning of the contract
>> itself.
>>
>
> Since the additional guarantees of both `open` and your proposed `closed`
> impose burdens on the library _author_ and offer more flexibility to the
> library _user_, I feel it is highly misleading to make them co-equal but
> antonyms. They are not the "opposite" of each other and the spelling would
> be misleading.
>
>
> They are not exactly antonyms, but if you think about this in terms of the
> set of cases, subclasses or conforming types their obvious 

Re: [swift-evolution] [Pitch] consistent public access modifiers - protocols

2017-02-10 Thread Matthew Johnson via swift-evolution

> On Feb 10, 2017, at 12:52 PM, Jordan Rose  wrote:
> 
> Hi, Matthew. Thank you for bringing up these issues. I'm going to break my 
> feedback up into separate messages, because I think really the enum and 
> protocol cases are unrelated. Open classes refer to classes that can be 
> subclassed from clients of the current module, and similarly open protocols 
> would be protocols that can be adopted from clients of the current module. 
> Public-but-not-open classes cannot be subclassed from outside the current 
> module, but they can still be subclassed within the module. By contrast, 
> "open" enums can grow new cases in new versions of the library, but clients 
> still can't add cases. (That's not a totally unreasonable feature to ever 
> consider, but it's not the one we need now.)

Hi Jordan.  Thanks for replying to my post!

I understand the current behavior of `open` and how it would work for 
protocols.  I also understand the vocabulary that has been used in talking 
about “open” enums thus far.  What I am trying to point out is that there are 
inconsistencies in the vocabulary we’ve been using thus far.  

The ideas of “open” and “closed” both talk about who is able to add to the set 
of cases / subclasses / conforming types.  `public` (without annotation) also 
does this.  But we haven’t been using the terms consistently - we use a 
different meaning depending on which kind of entity we’re talking about.

For example, as you pointed out, `open` currently means both a module *and* its 
clients can add new subclasses.  It doesn’t seem right to use this same 
terminology to mean the module can add cases to an enum but clients *can’t* add 
new cases to the enum.  I understand that “open” enums in the sense of the 
current meaning of the `open` keyword are not a feature we need right away.  I 
noted that this is specifically not proposed in my pitch.  But if we ever *do* 
add this feature, `open enum` seems like the right way to spell it (probably 
just using the existing case syntax in an extension to add cases in the client).

It’s also worth pointing out that `public` currently has three distinct 
meanings:
* `public` enums *cannot* have a new case added in a future version of the 
library is without a breaking change
* `public` classes *can* have a new subclass added in a future version of the 
library without a breaking change, but clients cannot add subclasses
* `public` protocols have the same semantics as `open` classes, allowing 
clients to add conforming types

If we want to move forward with *no* breaking change of any kind the situation 
gets worse:
* `open` enums can have new cases added in a future version of the library, but 
clients cannot add cases
* `closed` protocols behave like `public` classes while using the same 
terminology we use for enums with a fixed set of public cases (to which future 
versions of the library may not add to)

This all seems pretty unfortunate to me.  It seems somewhat confusing in a 
totally unnecessary way.  Everyone could learn to live with it, but why should 
we?  I think there is a very reasonable way to use this terminology 
consistently across all kinds of types.


> 
> This message will talk about protocols (and a bit about classes); I'll put my 
> thoughts on enums in another message.
> 
> I'm with you (and Adrian) in thinking "public-but-not-open" protocols are 
> useful. The Apple frameworks have a good handful of these, for cases where a 
> framework doesn't want to tie itself to a particular type, but still wants to 
> vend something with certain operations. Public-but-not-open protocols also 
> allow for non-public requirements, i.e. operations that every conforming type 
> has but only the library needs to call.

I’m glad to hear this!

> 
> However, we still have a hurdle here: is this useful enough to change the 
> defaults for it? Another way to implement this is to leave 'public' as is 
> (with its open-like behavior), but have an annotation to say that it can only 
> be conformed to from within the module. (`@closed public protocol Foo`) This 
> isn't necessarily what we would have done from the start, but breaks between 
> Swift 3 and Swift 4 have a higher bar to clear than between Swift 2 and Swift 
> 3.

This is certainly an option.  I feel like there is a pretty strong case for not 
going this route though: 

* Consistent use of terminology is pretty important.
* The decision to not pick a default between `public` and `open` classes was a 
good one which applies to protocols and enums as well.
* While it is a breaking change, the impact can be minimal with a multi-release 
rollout.

Many Swift users will run a migrator when upgrading to a new version of Swift.  
For these users, a simple mechanical migration will keep their code running 
without warnings through each version transition.  Users who don’t use the 
migrator will receive a warning in one version which becomes an error in the 
next, giving them 

Re: [swift-evolution] [Pitch] consistent public access modifiers - protocols

2017-02-10 Thread Adrian Zubarev via swift-evolution
Hello Jordan, having a clear and constructive opinion like yours is much 
appreciated in this topic.

As a disclaimer, I haven’t followed the original topic about the new open 
access modifier that much last year. At day one, when Swift 3 was released, I 
noticed open everywhere in Apples libraries like UIKit. I quickly had a short 
glance on how it supposed to work, because I literally run into the issue where 
the open is prohibited on initializers, which felt odd. Then I had a closer 
look to the proposal and realized it’s by design; but it still feels strange, 
because public-but-not-open claims to disallow overriding a type member from 
module A in module B, where open removes that restriction. Later on thinking 
how neat the differentiation between public and open was I thought, because 
it’s an ACCESS MODIFIER, it should work with any type we had in swift. Okay it 
doesn’t work with value types because they don’t have any sub-typing 
relationship which the client of my module could create - that’s totally fine 
by me. At the end of that journey I remembered that I had some protocols which 
I had to make public before Swift 3 because it was an implementation detail. 
Also it was really interesting to see that non of my protocols were open by 
default after the migration process. At that point I tried to open these 
protocols where I thought the client should be able to conform to them, because 
public should mean public-but-not-open right? And this is how I hit the wall 
with this.

I felt I had to share my experience on this.

Now that you’ve mentioned an alternative for protocols, such as @closed public. 
IMHO this would be a really shame if this was the final decision for this issue.

Iff we ever decide to bring sub-typing to value types, that would imply that 
we’d end up with open class/struct/enum vs. @closed public protocol, or even 
worse open class vs. @closed public protocols/struct/enum. It is simply saying 
inconsistent.

Having an exclusive access modifier for classes is simply not worth calling 
open an access modifier, because from the definitions it should affect all 
types and their members but not being exclusive to classes, otherwise it should 
have been open public, just like final public is.

Having an exclusive attribute for protocols, which only works with the public 
access modifier is nuts. Furthermore that would not only reserve the @closed 
attribute, but could potentially lead to even more inconsistency if we consider 
to add something like @closed to enums or elsewhere. In the current scenario 
@closed public has simply no other meaning than public on classes would have, 
but public would be open for protocols. o.O It definitely will become an origin 
of confusion at that point.

I understand that this is somehow a breaking change, but currently open feels 
simply as a rushed decision from last year. In its current state I think it’s a 
regression.

P.S.: Please don’t blame me for my horrible English. ;)



-- 
Adrian Zubarev
Sent with Airmail

Am 10. Februar 2017 um 19:52:23, Jordan Rose via swift-evolution 
(swift-evolution@swift.org) schrieb:

Hi, Matthew. Thank you for bringing up these issues. I'm going to break my 
feedback up into separate messages, because I think really the enum and 
protocol cases are unrelated. Open classes refer to classes that can be 
subclassed from clients of the current module, and similarly open protocols 
would be protocols that can be adopted from clients of the current module. 
Public-but-not-open classes cannot be subclassed from outside the current 
module, but they can still be subclassed within the module. By contrast, "open" 
enums can grow new cases in new versions of the library, but clients still 
can't add cases. (That's not a totally unreasonable feature to ever consider, 
but it's not the one we need now.)

This message will talk about protocols (and a bit about classes); I'll put my 
thoughts on enums in another message.

I'm with you (and Adrian) in thinking "public-but-not-open" protocols are 
useful. The Apple frameworks have a good handful of these, for cases where a 
framework doesn't want to tie itself to a particular type, but still wants to 
vend something with certain operations. Public-but-not-open protocols also 
allow for non-public requirements, i.e. operations that every conforming type 
has but only the library needs to call.

However, we still have a hurdle here: is this useful enough to change the 
defaults for it? Another way to implement this is to leave 'public' as is (with 
its open-like behavior), but have an annotation to say that it can only be 
conformed to from within the module. (`@closed public protocol Foo`) This isn't 
necessarily what we would have done from the start, but breaks between Swift 3 
and Swift 4 have a higher bar to clear than between Swift 2 and Swift 3.

It's worth noting that this can all be emulated by a struct with a non-public 
field of protocol type and forwarding 

Re: [swift-evolution] [Pitch] consistent public access modifiers - protocols

2017-02-10 Thread Jordan Rose via swift-evolution
Hi, Matthew. Thank you for bringing up these issues. I'm going to break my 
feedback up into separate messages, because I think really the enum and 
protocol cases are unrelated. Open classes refer to classes that can be 
subclassed from clients of the current module, and similarly open protocols 
would be protocols that can be adopted from clients of the current module. 
Public-but-not-open classes cannot be subclassed from outside the current 
module, but they can still be subclassed within the module. By contrast, "open" 
enums can grow new cases in new versions of the library, but clients still 
can't add cases. (That's not a totally unreasonable feature to ever consider, 
but it's not the one we need now.)

This message will talk about protocols (and a bit about classes); I'll put my 
thoughts on enums in another message.

I'm with you (and Adrian) in thinking "public-but-not-open" protocols are 
useful. The Apple frameworks have a good handful of these, for cases where a 
framework doesn't want to tie itself to a particular type, but still wants to 
vend something with certain operations. Public-but-not-open protocols also 
allow for non-public requirements, i.e. operations that every conforming type 
has but only the library needs to call.

However, we still have a hurdle here: is this useful enough to change the 
defaults for it? Another way to implement this is to leave 'public' as is (with 
its open-like behavior), but have an annotation to say that it can only be 
conformed to from within the module. (`@closed public protocol Foo`) This isn't 
necessarily what we would have done from the start, but breaks between Swift 3 
and Swift 4 have a higher bar to clear than between Swift 2 and Swift 3.

It's worth noting that this can all be emulated by a struct with a non-public 
field of protocol type and forwarding operations, but that's a lot of extra 
work today. We want to make the correct thing easy; in the face of writing a 
wrapper type, I suspect many library authors would just give up and make the 
protocol public.

I don't think the proposed "closed" for classes and protocols is interesting. 
"No new subclasses/adopters" seems only marginally useful for optimization, and 
not at all useful at a semantic level. "public-but-not-open" is the interesting 
access level.

That's about all I've got for protocols. Thanks again for bringing it up.
Jordan

P.S. For classes, note that 'final' is essentially a performance optimization 
at this point. I'm not even sure we should bother displaying it in generated 
interfaces (although the compiler should still be able to take advantage of it 
in clients).



> On Feb 8, 2017, at 15:05, Matthew Johnson via swift-evolution 
>  wrote:
> 
> I’ve been thinking a lot about our public access modifier story lately in the 
> context of both protocols and enums.  I believe we should move further in the 
> direction we took when introducing the `open` keyword.  I have identified 
> what I think is a promising direction and am interested in feedback from the 
> community.  If community feedback is positive I will flesh this out into a 
> more complete proposal draft.
> 
> 
> Background and Motivation:
> 
> In Swift 3 we had an extended debate regarding whether or not to allow 
> inheritance of public classes by default or to require an annotation for 
> classes that could be subclassed outside the module.  The decision we reached 
> was to avoid having a default at all, and instead make `open` an access 
> modifier.  The result is library authors are required to consider the 
> behavior they wish for each class.  Both behaviors are equally convenient 
> (neither is penalized by requiring an additional boilerplate-y annotation).
> 
> A recent thread 
> (https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170206/031566.html
>  
> )
>  discussed a similar tradeoff regarding whether public enums should commit to 
> a fixed set of cases by default or not.  The current behavior is that they 
> *do* commit to a fixed set of cases and there is no option (afaik) to modify 
> that behavior.  The Library Evolution document 
> (https://github.com/apple/swift/blob/master/docs/LibraryEvolution.rst#enums 
> ) 
> suggests a desire to change this before locking down ABI such that public 
> enums *do not* make this commitment by default, and are required to opt-in to 
> this behavior using an `@closed` annotation.
> 
> In the previous discussion I stated a strong preference that closed enums 
> *not* be penalized with an additional annotation.  This is because I feel 
> pretty strongly that it is a design smell to: 1) expose cases publicly if 
> consumers of the API are not expected to switch on them and 2) require users 
> to handle unknown future cases if they are likely to switch over 

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-10 Thread Matthew Johnson via swift-evolution

> On Feb 10, 2017, at 1:06 AM, Xiaodi Wu  wrote:
> 
> On Thu, Feb 9, 2017 at 9:57 AM, Matthew Johnson  > wrote:
> 
>> On Feb 8, 2017, at 5:48 PM, Xiaodi Wu > > wrote:
>> 
>> I agree very much with rationalizing access levels, but I'm not sure I like 
>> this proposal for public vs. closed. How would the compiler stop me from 
>> editing my own code if something is closed? The answer must be that it 
>> can't, so I can't see it as a co-equal to open but rather simply a statement 
>> of intention. Therefore I think use cases for the proposed behavior of 
>> closed would be better served by annotations and proper semantic versioning.
> 
> The most important point IMO is that they *are* co-equal in the sense that 
> they define a contract between library authors, library users and the 
> compiler.
> 
> Certainly, `open` and your proposed `closed` both represent contracts among 
> library authors, users, and the compiler. But so do other features that are 
> not access modifiers--unless your intent is to make all the (not yet totally 
> finalized) resilience attributes such as `@inlineable` become access 
> modifiers. That both `open` and the proposed `closed` are both contracts 
> doesn't make them both access modifiers.

This is a good point.  But `open`, `closed` and `public` have something very 
important in common: they all have meaning with regarding the set of cases, 
subclasses or conforming types and are mutually exclusive in the contract they 
offer in this regard.

> 
> To me, the reason one _could_ justify `open` being spelled like an access 
> modifier (which I was not supportive of, actually, though I was fine with 
> `public` not allowing subclassing) is that it quacks like an access modifier 
> in some ways. In particular, since it offers more "access" to a class than 
> does `public` by allowing subclassing, one can argue that it fits at the top 
> of a hierarchy of access levels.
> 
> As you define it, `closed` also makes additional guarantees to the end user 
> than does `public` by (self-)imposing restrictions on the library author. 
> Thus, it does not fit into a hierarchy of access modifiers where each level 
> is more "accessible" than the next. Put another way, my point here is that 
> `closed` is not the opposite of `open` in key ways, as the names might 
> suggest. In fact, from the perspective of a library user, both `closed` and 
> `open` would allow you to do more than `public`.

You make a great point here when you say that `closed` makes additional 
guarantees to the end user, beyond `public`.  `closed` and `open` both give 
users more capabilities by placing additional burden on the library.  In a very 
real sense `closed` *does* provide more visibility to information about the 
type - it guarantees knowledge of the *complete* set of cases, subclasses or 
protocols both now and in the future (modulo breaking changes).  In this sense 
it can be said to be “more accessible than public”.  This does form a strict 
hierarchy, just not a linear one:

private
  |
  fileprivate
  |
internal
  |
 public
/ \
closed  open

I admit that the name `closed` doesn’t *sounds* more accessible.  Maybe there 
is a better name?  But `closed` is the name we have all been using for this 
contract and it offers a nice symmetry with open.  One opens the set of cases, 
subclasses, or conforming types to users.  The other closes off the ability of 
the library to add to or hide any members of the set of cases, subclasses or 
conforming types.  The symmetry is in the fact that they both say something 
about the totality of the set of cases, subclasses or conforming types.

It’s also worth noting that a `public` type can become `closed` or `open` in a 
future version of a library, but once `closed` or `open` that option is fixed 
forever (modulo breaking changes).  This also suggests the hierarchy I 
visualized above.

> 
> As you note, there are some differences in how the `closed` contract is 
> supported.  But that is far less important than the meaning of the contract 
> itself.
> 
> Since the additional guarantees of both `open` and your proposed `closed` 
> impose burdens on the library _author_ and offer more flexibility to the 
> library _user_, I feel it is highly misleading to make them co-equal but 
> antonyms. They are not the "opposite" of each other and the spelling would be 
> misleading.

They are not exactly antonyms, but if you think about this in terms of the set 
of cases, subclasses or conforming types their obvious meaning does make sense. 
 `closed` says to users: “you know the complete set”.  `open` says to users: 
“you are allowed to add to the set”.

I suppose this suggests a possible alternative name: `complete`.  That would 
avoid 

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-09 Thread Matthew Johnson via swift-evolution

> On Feb 9, 2017, at 10:33 AM, Adrian Zubarev  
> wrote:
> 
> The last explanation is great, now I could follow the idea behind the 
> proposed closed keyword/access modifier. I do now understand the contract on 
> enums, but I’m struggling to understand how closed would work in my own 
> codebase. Assume I had a closed (not the public meaning of your proposal) 
> protocol.
> 
> Am I allowed to conform to that protocol inside my library? If it’s a version 
> controlled feature, how to prevent further conformance to that protocol in a 
> newer version?
> 
Yes, you are allowed to have as many conforming types inside the library as you 
wish, as long as the conformances are introduced alongside the protocol.  New 
conformances may not be added in future versions.

I don’t know exactly what the enforcement mechanism would look like, but I 
imagine it would be similar or identical to the mechanism used for `closed` 
enums.  Maybe someone from the core team can elaborate on what this will look 
like.
> What would an access modifier like closed mean on type members (final 
> public)? If it’s only a type scope access modifier, it leans towards being an 
> attribute instead.
> 
I hadn’t considered this yet but it’s a good question.  I don’t have time to 
consider it deeply, but I think the implication for members is that all 
overrides are public and no new overrides will be added in the future.  It 
isn’t likely to be useful in this case, but I think we could provide a clear 
definition.
> If it’s not an access modifier, would closed have some versioning paramerters?
> Bikeshedding: @closed(1.0.0) (The version, the type was closed)
> On current enums: @closed(*) (From the start)
Good question.  This is what the Library Evolution document has to say:

@closed is a versioned attribute. This is so that clients can deploy against 
older versions of the library, which may have non-public cases in the enum. (In 
this case the client must manipulate the enum as if the @closed attribute were 
absent.) All cases that are not versioned become implicitly versioned with this 
number.

I would prefer to see `closed` be an access modifier so it isn’t penalized with 
verbosity, particularly for enums.  I think the best approach is that `closed` 
with no version specifier is allowed if it is included in the initial release 
of a module.  `public` enums may be changed to `closed(n.m.x)` in future 
versions of a module.  There is already precedent for parameterized access 
modifiers: `private(set)`.

> The latter implies in my head that each type needs an explicit version 
> annotation like @available(1.0.0, *)!?
> 
No, I don’t think so.
> How do we handle bug fixes on closed types? Assume all current enums would 
> get an annotation like @closed(*) public. After normalize enum case 
> representation proposal 
> 
>  you might also want to clean up the names of your cases. That means you have 
> to perform a breaking API change.
Both proposals would be part of Swift 4. No module would be able to publish a 
production-ready version until Swift 4 is released.  Also, `closed` wouldn’t 
have ABI implications until ABI is locked down, which won’t happen until Swift 
4 is released (or later).  So you would have the chance to clean up case names 
at the same time as you introduce `closed`.

It’s also worth pointing out that changing a case name is going to be a 
breaking change regardless of whether an enum is `closed` or not.  It might be 
possible to minimize the impact of these changes if there was a way to specify 
the prior, deprecated name for the case, but this issue is orthogonal to 
`closed`.
> For example in one of my ‘just for fun’ projects I have two enum cases that 
> look as follows:
> 
> case javaScript(String)
> case scopedJavaScript(String, scope: Document)
> If the mentioned proposal will be accepted I’d like to make these cases shiny.
> 
> // v1:
> case javaScript(String)
> case javaScript(String, scope: Document)
>  
> // or v2:
> case javaScript(String, scope: Document? = nil)
> 
> 
> 
> -- 
> Adrian Zubarev
> Sent with Airmail
> 
> Am 9. Februar 2017 um 16:57:40, Matthew Johnson via swift-evolution 
> (swift-evolution@swift.org ) schrieb:
> 
>> 
>>> On Feb 8, 2017, at 5:48 PM, Xiaodi Wu >> > wrote:
>>> 
>>> I agree very much with rationalizing access levels, but I'm not sure I like 
>>> this proposal for public vs. closed. How would the compiler stop me from 
>>> editing my own code if something is closed? The answer must be that it 
>>> can't, so I can't see it as a co-equal to open but rather simply a 
>>> statement of intention. Therefore I think use cases for the proposed 
>>> behavior of closed would be better served by annotations and proper 
>>> 

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-09 Thread Matthew Johnson via swift-evolution

> On Feb 8, 2017, at 7:02 PM, Adrian Zubarev via swift-evolution 
>  wrote:
> 
> Hurray, I cannot wait to get the consistent behavior of open/public 
> protocols. I’m not sure I could follow the idea behind the proposed closed 
> keyboard/access modifier. It almost felt like closed == final public, am I 
> mistaken something here?
> 


The best way to think about `closed` is to just think about `public enum` as it 
exists today.  The contract implies that no new cases will be added because 
user code is allowed to perform exhaustive switch over the cases.  Adding a 
case is a breaking change.

The insight behind this proposal is that we can also support these semantics 
with classes and protocols.  A `closed` class may have subclasses within the 
module so long as they are public, but no direct subclasses may be added in 
future versions (descendants may still be added if the `closed` class has a 
non-final subclass).  Adding a subclass in the future becomes a breaking change.

Similarly with protocols, no new conformances will be added in future versions 
of the library.  As with `closed` classes, if a non-final class conforms to a 
`closed` protocol subclasses may still be added in the future.

The relationship between `closed` and `final public` is interesting.  `final 
public` is equivalent to `final closed` under this proposal as long as the 
semantics of `final` implies not only that there are no subclasses *right now*, 
but also that  that no subclasses will ever be added *in the future*.  This is 
the semantics suggested in the Library Evolution document - "final may not be 
removed from a class or its members. (The presence of final enables 
optimization.)”.  This is a degenerate case of `closed`: new subclasses cannot 
be added because `final` declares that there will *never be* any subclasses.
> Furthermore, I really would love if the community could revisit how 
> open/public really should behave. When open was implemented and I tried it 
> out without reading the proposal first I bumped into things like open init() 
> which felt really odd. I understand the argumentation from the proposal, but 
> it feels wrong and inconsistent to me.
> 
> Here’s how I would have imagined open vs. public. IMHO public should really 
> mean, you cannot subclass, conform or override something in module B from 
> module A.
> 
> Modified samples from SE–0117:
> 
> // This class is not subclassable outside of ModuleA.
> public class NonSubclassableParentClass {
> // This method >is not overridable outside of ModuleA.
> public func foo() {}
> 
> // This method is not overridable outside of ModuleA because
> // its class restricts its access level.
> // It is INVALID to declare it as `open`.
> public func bar() {}
> 
> // The behavior of `final` methods remains unchanged.
> public final func baz() {}
> }
> 
> // This class is subclassable both inside and outside of ModuleA.
> open class SubclassableParentClass {
>  
> // Designated initializer that is not overridable outside ModuleA
> public init()
>  
> // Another designated initializer that is overridable outside ModuleA
> open init(foo: Int)
>  
> // This property is not overridable outside of ModuleA.
> public var size : Int
> 
> // This method is not overridable outside of ModuleA.
> public func foo() {}
> 
> // This method is overridable both inside and outside of ModuleA.
> open func bar() {}
> 
> /// The behavior of a `final` method remains unchanged.
> public final func baz() {}
> }
> 
> /// The behavior of `final` classes remains unchanged.
> public final class FinalClass { }
> /// ModuleB:
> 
> import ModuleA
> 
> // This is allowed since the superclass is `open`.
> class SubclassB : SubclassableParentClass {
>  
> // Iff certain conditions are met, the superclass initializers are 
> inherited.
> // `init` will stay `public` and won't be overridable.
> //
> // If the conditions are not met, then `init` is not inherited. That does 
> not
> // mean that we can create a new designated `init` that matches it's 
> superclass's
> // designated initializer. The behavior should be consistent, like the  
> // superclass's function `foo` is reserved and not overridable, so is 
> `init`
> // reserved in this case and not overridable.
>  
> // This is allowed since the superclass's initializer is `open`
> override init(foo: Int) {
> super.init(foo: foo)
> }
>  
> init(bar: Int) {
> // We could call a super designated initializer from here
> super.init()
> // or
> super.init(foo: bar)
> }
>  
> // This is invalid because it overrides a method that is
> // defined outside of the current module but is not `open'.
> override func foo() { }
> 
> // This is allowed since the superclass's method is overridable.
> // It does not 

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-09 Thread Matthew Johnson via swift-evolution

> On Feb 8, 2017, at 5:48 PM, Xiaodi Wu  wrote:
> 
> I agree very much with rationalizing access levels, but I'm not sure I like 
> this proposal for public vs. closed. How would the compiler stop me from 
> editing my own code if something is closed? The answer must be that it can't, 
> so I can't see it as a co-equal to open but rather simply a statement of 
> intention. Therefore I think use cases for the proposed behavior of closed 
> would be better served by annotations and proper semantic versioning.

The most important point IMO is that they *are* co-equal in the sense that they 
define a contract between library authors, library users and the compiler.  As 
you note, there are some differences in how the `closed` contract is supported. 
 But that is far less important than the meaning of the contract itself.

Dave's comment about tools to assist with contract-compatible API evolution is 
the right way to think about this.  Of course you *can* make breaking changes, 
but we want to make it clear when you *are* making a breaking change, both for 
source and for ABI compatibility.  This will help library authors, but it also 
helps users as well as the compiler reason about code when we are able to offer 
stronger guarantees.

Most notably, the behavior of public enums *already* has the API contract of 
`closed` and we do not want to remove that capability.  This proposal only 
formalizes how that contract is specified and makes it consistent across all 
kinds of types.  It *does not* introduce the idea of a closed semantic contract 
for a type.

> As this change didn't seem in scope for Swift 4 phase 1, I've held off on 
> discussing my own thoughts on access levels. The idea I was going to propose 
> in phase 2 was to have simply open and public enums (and protocols). I really 
> think that completes access levels in a rational way without introducing 
> another keyword.

The reason I posted now is because formalizing this API contract for enums must 
happen before ABI is locked down, and also because there is at least one 
protocol in the standard library (`MirrorPath`) which is documented with the 
intent that it be `closed`.

I understand the reluctance to introduce another keyword.  It isn’t clear to me 
what semantics you assign to `open` and `public` enums.

Are you suggesting that they match the semantics defined in my proposal and 
suggesting closed enums (i.e. matching the current behavior of `public` enums) 
would require an `@closed` annotation as suggested in the Library Evolution 
document?  I am opposed to this approach because it penalizes the API contract 
that I think is often the most appropriate for enums.  I strongly prefer that 
we adopt the same neutral stance that we when we introduced `open`.  

On the other hand, you might be suggesting that `public` enums maintain their 
current behavior and we simply introduce `open` as a modifier that reserves the 
right for the *library* to introduce new cases while continuing to prohibit 
*users* from introducing new cases.  This approach has inconsistent semantics 
for both `public` and `open`.  These keywords would indicate a different API 
contract for enums than they do for classes and protocols.  In fact, `open` for 
enums would have a contract analagous with `public` for classes and protocols.  
This feels like a recipe for confusion.  IMO, having consistent semantics for 
each keyword is pretty important.  We already have, and desire to continue to 
have, three distinct semantic contracts.  If we want keywords with consistent 
semantics we are going to have to introduce a new keyword for the third meaning.


> On Wed, Feb 8, 2017 at 17:05 Matthew Johnson via swift-evolution 
> > wrote:
> I’ve been thinking a lot about our public access modifier story lately in the 
> context of both protocols and enums.  I believe we should move further in the 
> direction we took when introducing the `open` keyword.  I have identified 
> what I think is a promising direction and am interested in feedback from the 
> community.  If community feedback is positive I will flesh this out into a 
> more complete proposal draft.
> 
> 
> Background and Motivation:
> 
> In Swift 3 we had an extended debate regarding whether or not to allow 
> inheritance of public classes by default or to require an annotation for 
> classes that could be subclassed outside the module.  The decision we reached 
> was to avoid having a default at all, and instead make `open` an access 
> modifier.  The result is library authors are required to consider the 
> behavior they wish for each class.  Both behaviors are equally convenient 
> (neither is penalized by requiring an additional boilerplate-y annotation).
> 
> A recent thread 
> (https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170206/031566.html
>  
> 

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-08 Thread Dave Abrahams via swift-evolution

on Wed Feb 08 2017, Xiaodi Wu  wrote:

> I agree very much with rationalizing access levels, but I'm not sure I like
> this proposal for public vs. closed. How would the compiler stop me from
> editing my own code if something is closed? The answer must be that it
> can't, so I can't see it as a co-equal to open but rather simply a
> statement of intention. 

IMO we are eventually going to need to have tools for analyzing ABI and
API breakage.  It's reasonable to think that such tools might be built
into the compiler.

-- 
-Dave

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


Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-08 Thread Adrian Zubarev via swift-evolution
Hurray, I cannot wait to get the consistent behavior of open/public protocols. 
I’m not sure I could follow the idea behind the proposed closed keyboard/access 
modifier. It almost felt like closed == final public, am I mistaken something 
here?

Furthermore, I really would love if the community could revisit how open/public 
really should behave. When open was implemented and I tried it out without 
reading the proposal first I bumped into things like open init() which felt 
really odd. I understand the argumentation from the proposal, but it feels 
wrong and inconsistent to me.

Here’s how I would have imagined open vs. public. IMHO public should really 
mean, you cannot subclass, conform or override something in module B from 
module A.

Modified samples from SE–0117:

// This class is not subclassable outside of ModuleA.
public class NonSubclassableParentClass {
// This method >is not overridable outside of ModuleA.
public func foo() {}

// This method is not overridable outside of ModuleA because
// its class restricts its access level.
// It is INVALID to declare it as `open`.
public func bar() {}

// The behavior of `final` methods remains unchanged.
public final func baz() {}
}

// This class is subclassable both inside and outside of ModuleA.
open class SubclassableParentClass {
 
// Designated initializer that is not overridable outside ModuleA
public init()
 
// Another designated initializer that is overridable outside ModuleA
open init(foo: Int)
 
// This property is not overridable outside of ModuleA.
public var size : Int

// This method is not overridable outside of ModuleA.
public func foo() {}

// This method is overridable both inside and outside of ModuleA.
open func bar() {}

/// The behavior of a `final` method remains unchanged.
public final func baz() {}
}

/// The behavior of `final` classes remains unchanged.
public final class FinalClass { }
/// ModuleB:

import ModuleA

// This is allowed since the superclass is `open`.
class SubclassB : SubclassableParentClass {
 
// Iff certain conditions are met, the superclass initializers are 
inherited.
// `init` will stay `public` and won't be overridable.
//
// If the conditions are not met, then `init` is not inherited. That does 
not
// mean that we can create a new designated `init` that matches it's 
superclass's
// designated initializer. The behavior should be consistent, like the  
// superclass's function `foo` is reserved and not overridable, so is `init`
// reserved in this case and not overridable.
 
// This is allowed since the superclass's initializer is `open`
override init(foo: Int) {
super.init(foo: foo)
}
 
init(bar: Int) {
// We could call a super designated initializer from here
super.init()
// or
super.init(foo: bar)
}
 
// This is invalid because it overrides a method that is
// defined outside of the current module but is not `open'.
override func foo() { }

// This is allowed since the superclass's method is overridable.
// It does not need to be marked `open` because it is defined on
// an `internal` class.
override func bar() { }
}
required should always match the same scope level as the type in which it’s 
defined. That means if the class is open, than any of it’s required 
initializers will be open as well.



-- 
Adrian Zubarev
Sent with Airmail

Am 9. Februar 2017 um 00:49:04, Xiaodi Wu via swift-evolution 
(swift-evolution@swift.org) schrieb:

I agree very much with rationalizing access levels, but I'm not sure I like 
this proposal for public vs. closed. How would the compiler stop me from 
editing my own code if something is closed? The answer must be that it can't, 
so I can't see it as a co-equal to open but rather simply a statement of 
intention. Therefore I think use cases for the proposed behavior of closed 
would be better served by annotations and proper semantic versioning.

As this change didn't seem in scope for Swift 4 phase 1, I've held off on 
discussing my own thoughts on access levels. The idea I was going to propose in 
phase 2 was to have simply open and public enums (and protocols). I really 
think that completes access levels in a rational way without introducing 
another keyword.
On Wed, Feb 8, 2017 at 17:05 Matthew Johnson via swift-evolution 
 wrote:
I’ve been thinking a lot about our public access modifier story lately in the 
context of both protocols and enums.  I believe we should move further in the 
direction we took when introducing the `open` keyword.  I have identified what 
I think is a promising direction and am interested in feedback from the 
community.  If community feedback is positive I will flesh this out into a more 
complete proposal draft.


Background and Motivation:

In Swift 3 we had an extended debate 

Re: [swift-evolution] [Pitch] consistent public access modifiers

2017-02-08 Thread Xiaodi Wu via swift-evolution
I agree very much with rationalizing access levels, but I'm not sure I like
this proposal for public vs. closed. How would the compiler stop me from
editing my own code if something is closed? The answer must be that it
can't, so I can't see it as a co-equal to open but rather simply a
statement of intention. Therefore I think use cases for the proposed
behavior of closed would be better served by annotations and proper
semantic versioning.

As this change didn't seem in scope for Swift 4 phase 1, I've held off on
discussing my own thoughts on access levels. The idea I was going to
propose in phase 2 was to have simply open and public enums (and
protocols). I really think that completes access levels in a rational way
without introducing another keyword.
On Wed, Feb 8, 2017 at 17:05 Matthew Johnson via swift-evolution <
swift-evolution@swift.org> wrote:

> I’ve been thinking a lot about our public access modifier story lately in
> the context of both protocols and enums.  I believe we should move further
> in the direction we took when introducing the `open` keyword.  I have
> identified what I think is a promising direction and am interested in
> feedback from the community.  If community feedback is positive I will
> flesh this out into a more complete proposal draft.
>
>
> Background and Motivation:
>
> In Swift 3 we had an extended debate regarding whether or not to allow
> inheritance of public classes by default or to require an annotation for
> classes that could be subclassed outside the module.  The decision we
> reached was to avoid having a default at all, and instead make `open` an
> access modifier.  The result is library authors are required to consider
> the behavior they wish for each class.  Both behaviors are equally
> convenient (neither is penalized by requiring an additional boilerplate-y
> annotation).
>
> A recent thread (
> https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170206/031566.html)
> discussed a similar tradeoff regarding whether public enums should commit
> to a fixed set of cases by default or not.  The current behavior is that
> they *do* commit to a fixed set of cases and there is no option (afaik) to
> modify that behavior.  The Library Evolution document (
> https://github.com/apple/swift/blob/master/docs/LibraryEvolution.rst#enums)
> suggests a desire to change this before locking down ABI such that public
> enums *do not* make this commitment by default, and are required to opt-in
> to this behavior using an `@closed` annotation.
>
> In the previous discussion I stated a strong preference that closed enums
> *not* be penalized with an additional annotation.  This is because I feel
> pretty strongly that it is a design smell to: 1) expose cases publicly if
> consumers of the API are not expected to switch on them and 2) require
> users to handle unknown future cases if they are likely to switch over the
> cases in correct use of the API.
>
> The conclusion I came to in that thread is that we should adopt the same
> strategy as we did with classes: there should not be a default.
>
> There have also been several discussions both on the list and via Twitter
> regarding whether or not we should allow closed protocols.  In a recent
> Twitter discussion Joe Groff suggested that we don’t need them because we
> should use an enum when there is a fixed set of conforming types.  There
> are at least two  reasons why I still think we *should* add support for
> closed protocols.
>
> As noted above (and in the previous thread in more detail), if the set of
> types (cases) isn’t intended to be fixed (i.e. the library may add new
> types in the future) an enum is likely not a good choice.  Using a closed
> protocol discourages the user from switching and prevents the user from
> adding conformances that are not desired.
>
> Another use case supported by closed protocols is a design where users are
> not allowed to conform directly to a protocol, but instead are required to
> conform to one of several protocols which refine the closed protocol.
> Enums are not a substitute for this use case.  The only option is to resort
> to documentation and runtime checks.
>
>
> Proposal:
>
> This proposal introduces the new access modifier `closed` as well as
> clarifying the meaning of `public` and expanding the use of `open`.  This
> provides consistent capabilities and semantics across enums, classes and
> protocols.
>
> `open` is the most permissive modifier.  The symbol is visible outside the
> module and both users and future versions of the library are allowed to add
> new cases, subclasses or conformances.  (Note: this proposal does not
> introduce user-extensible `open` enums, but provides the syntax that would
> be used if they are added to the language)
>
> `public` makes the symbol visible without allowing the user to add new
> cases, subclasses or conformances.  The library reserves the right to add
> new cases, subclasses or conformances in a future version.
>
>