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