I still don't see the use case for this. Perhaps I'm wrong, but if an API 
creates a protocol for the sole purpose of representing a set of concrete 
types, that looks more to me like bad API design, and not a missing feature in 
the language. Can you give me a small concrete real-world example of an API 
which requires that? 

> On 19 Feb 2017, at 16:10, Matthew Johnson via swift-evolution 
> <swift-evolution@swift.org> wrote:
> 
> 
> 
> Sent from my iPad
> 
>> On Feb 19, 2017, at 12:58 AM, David Waite <da...@alkaline-solutions.com> 
>> wrote:
>> 
>> I am unsure if this feature is a good idea. Does someone have a real-world 
>> use for this which isn’t just hiding strong implementation coupling behind a 
>> protocol?
> 
> Yes.  If this proposal moves ahead we can implement an API that takes a 
> hereogenous collection with implicit conversion for several different 
> concrete types while ensuring that all elements are of a type provided by the 
> library:
> 
> public protocol Foo {}
> public struct One: Foo {}
> public struct Two: Foo {}
> // other conforming types in the library
> 
> func takesFoos(_ foos: [Foo]) {}
> 
> // in user code:
> takesFoos([One(), One(), Two(), One()])
> 
> This use case could be subsumed by enums if we implement some of the ideas in 
> my value subtyping manifesto but those are for the future and may or may not 
> be accepted.  This is a relatively small change that can e made in Swift 4.
> 
>> When I consume a protocol, it is under the assumption that the protocol is 
>> documented such that I would be able to work against *any* implementation of 
>> the protocol. With a closed protocol, I would have to assume that there are 
>> significant side effects, either undocumented or difficult for a third party 
>> to duplicate. To my experience, that sounds brittle.
>> 
>> Assuming you aren’t switching on the implementing type of a protocol (which 
>> itself can be a sign that your design isn’t properly using polymorphism), 
>> one could get this design by creating a struct with the interface desired, 
>> and passing invocations through to an internal protocol reference.
>> 
>> -DW
>> 
>>> On Feb 18, 2017, at 1:41 PM, Matthew Johnson via swift-evolution 
>>> <swift-evolution@swift.org> wrote:
>>> 
>>> Now that we’re in phase 2 I’d like to officially propose we introduce 
>>> `open` protocols and require conformances to  `public` protocols be inside 
>>> the declaring module.  Let’s use this thread for feedback on the official 
>>> proposal.  After a healthy round of discussion I’ll open a PR to submit it 
>>> for review.
>>> 
>>> 
>>> # Feature name
>>> 
>>> * Proposal: [SE-NNNN](NNNN-open-public-protocols.md)
>>> * Authors: [Matthew Johnson](https://github.com/anandabits)
>>> * Review Manager: TBD
>>> * Status: **Awaiting review**
>>> 
>>> ## Introduction
>>> 
>>> This proposal introduces `open protocol` and changes the meaning of `public 
>>> protocol` to match the meaning of `public class` (in this case, 
>>> conformances are only allowed inside the declaring module).
>>> 
>>> The pitch thread leading up to this proposal was: [consistent public access 
>>> modifiers](https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170206/031653.html)
>>> 
>>> ## Motivation
>>> 
>>> A general principle the Swift community has adopted for access control is 
>>> that defaults should reserve maximum flexibility for a library.  The 
>>> ensures that any capabilities beyond mere visibility are not available 
>>> unless the author of the library has explicitly declared their intent that 
>>> the capabilities be made available.  Finally, when it is possible to switch 
>>> from one semantic to another without breaking clients (but not vice-versa) 
>>> we should prefer the more forgiving (i.e. fixable) semantic as the (soft) 
>>> default.
>>> 
>>> `public` is considered a "soft default" in the sense that it is the first 
>>> access modifier a user will reach for when exposing a declaration outside 
>>> of the module.  In the case of protocols the current meaning of `public` 
>>> does not meet the principle of preserving maximum flexibility for the 
>>> author of the library.  It allows users of the library to conform to the 
>>> protocol.
>>> 
>>> There are good reasons a library may not wish to allow users to add 
>>> conformances to a protocol.  For example, it may not wish to expose the 
>>> conforming concrete types.  While similar behavior could be accomplished 
>>> with an enum if cases could be private, that requires an implementation to 
>>> use switch statements rather than polymorphism.
>>> 
>>> Even if all the conforming types are also public there are cases where 
>>> polymorphism is the preferred implementation.  For example, if the set of 
>>> conforming types is not expected to be fixed (despite all being inside the 
>>> library) the authors may not want to have to maintain switch statements 
>>> every time they need to add or remove a confroming type which would be 
>>> necessary if an enum were used instead.  Polymorphism allows us to avoid 
>>> this, giving us the ability to add and remove conforming types within the 
>>> implementation of the library without the burden of maintaining switch 
>>> statements.
>>> 
>>> Aligning the access modifiers for protocols and classes allows us to 
>>> specify both conformable and non-conformable protocols, provides a soft 
>>> default that is consistent with the principle of (soft) defaults reserving 
>>> maximum flexibility for the library, and increases the overall consistency 
>>> of the language by aligning the semantics of access control for protocols 
>>> and classes.
>>> 
>>> The standard library currently has at least one protocol (`MirrorPath`) 
>>> that is documented as disallowing client conformances.  If this proposal is 
>>> adopted it is likely that `MirrorPath` would be declared `public protocol` 
>>> and not `open protocol`.
>>> 
>>> Jordan Rose has indicated that the Apple frameworks also include a number 
>>> of protocols documented with the intent that users do not add conformances. 
>>>  Perhaps an importer annotation would allow the compiler to enforce these 
>>> semantics in Swift code as well.
>>> 
>>> ## Proposed solution
>>> 
>>> The proposed solution is to change the meaning of `public protocol` to 
>>> disallow conformances outside the declaring module and introduce `open 
>>> protocol` to allow conformances outside the decalring module (equivalent to 
>>> the current meaning of `public protocol`).
>>> 
>>> ## Detailed design
>>> 
>>> The detailed design is relatively straightforward but there are three 
>>> important wrinkles to consider.
>>> 
>>> ### User refinement of public protocols
>>> 
>>> Consider the following example:
>>> 
>>> ```swift
>>> // Library module:
>>> public protocol P {}
>>> public class C: P {}
>>> 
>>> // User module:
>>> protocol User: P {}
>>> extension C: User {}
>>> ```
>>> 
>>> The user module is allowed to add a refinement to `P` because this does not 
>>> have any impact on the impelementation of the library or its possible 
>>> evolution.  It simply allows the user to write code that is generic over a 
>>> subset of the conforming types provided by the library.
>>> 
>>> ### Public protocols with open conforming classes
>>> 
>>> Consider the following example:
>>> 
>>> ```swift
>>> public protocol P P{}
>>> open class C: P {}
>>> ```
>>> 
>>> Users of this module will be able to add subclasses of `C` that have a 
>>> conformance to `P`.  This is allowed becuase the client of the module did 
>>> not need to explicitly declare a conformance and the module has explicitly 
>>> stated its intent to allow subclasses of `C` with the `open` access 
>>> modifier.
>>> 
>>> ### Open protocols that refine public protocols
>>> 
>>> Consider the following example:
>>> 
>>> ```swift
>>> // library module:
>>> public protocol P {}
>>> open protocol Q: P {}
>>> open protocol R: P {}
>>> 
>>> // user module:
>>> struct S: P {} // error `P` is not `open`
>>> struct T: Q {} // ok
>>> struct U: R {} // ok
>>> ```
>>> 
>>> The user module is allowed to introudce a conformance to `P`, but only 
>>> indirectly by also conforming to `Q`.  The meaning we have ascribed to the 
>>> keywords implies that this should be allowed and it offers libraries a very 
>>> wide design space from which to choose.  The library is able to have types 
>>> that conform directly to `P`, while placing additional requirements on user 
>>> types if necessary.
>>> 
>>> ## Source compatibility
>>> 
>>> This proposal breaks source compatibility, but in a way that allows for a 
>>> simple mechanical migration.  A multi-release stratgegy will be used to 
>>> roll out this proposal to provide maximum possible source compatibility 
>>> from one release to the next.
>>> 
>>> 1. In Swift 4, introduce the `open` keyword and the `@nonopen` attribute 
>>> (which can be applied to `public protocol` to give it the new semantics of 
>>> `public`).
>>> 2. In Swift 4 (or 4.1 if necessary) start warning for `public protocol` 
>>> with no annotation.
>>> 3. In the subsequent release `public protocol` without annotation becomes 
>>> an error.
>>> 4. In the subsequent relase `public protocol` without annotation takes on 
>>> the new semantics.
>>> 5. `@nonopen` becomes a warning, and evenutally an erro as soon as we are 
>>> comfortable making those changes.
>>> 
>>> ## Effect on ABI stability
>>> 
>>> I would appreciate it if others can offer input regarding this section.  I 
>>> believe this proposal has ABI consequences, but it's possible that it could 
>>> be an additivie ABI change where the ABI for conformable protocols remains 
>>> the same and we add ABI for non-conformable protocols later.  If that is 
>>> possible, the primary impact would be the ABI of any standard library 
>>> protocols that would prefer to be non-conformable.
>>> 
>>> ## Effect on API resilience
>>> 
>>> This proposal would may impact one or more protocols in the standard 
>>> library, such as `MirrorPath`, which would likely choose to remain `public` 
>>> rather than adopt `open`.
>>> 
>>> ## Alternatives considered
>>> 
>>> The primary alternatives are to either make no change, or to add something 
>>> like `closed protocol`.  The issues motivating the current proposal as a 
>>> better alternative than either of these options are covered in the 
>>> motivation section.
>>> 
>>> _______________________________________________
>>> 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

Reply via email to