Just FYI, I solved this issue in my own library (which included a json jpointer implementation) via:
public enum SubscriptParameter { case string(String) case int(Int) } extension SubscriptParameter : ExpressibleByIntegerLiteral { public init(integerLiteral value: Int) { self = .int(value) } } extension SubscriptParameter : ExpressibleByStringLiteral { public init(stringLiteral value: String) { self = .string(value) } public init(extendedGraphemeClusterLiteral value: String) { self.init(stringLiteral: value) } public init(unicodeScalarLiteral value: String) { self.init(stringLiteral: value) } } extension SubscriptParameter : CustomStringConvertible { public var description: String { switch self { case .string(let str): return "\"\(str)\"" case .int(let i): return String(i) } } } func debug(_ path:SubscriptParameter...) { print("path is \(path)") } debug(1, "foo", 2, "bar”) // path is [1, “foo”, 2, “bar”] > On Feb 19, 2017, at 1:14 AM, Adrian Zubarev <adrian.zuba...@devandartist.com> > wrote: > > If you haven’t followed the other thread Matthew previously opened than you > have missed the example I showed there. > > Here it is again: > > 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? { … } > The absence of closed protocols forced me to create a special requirement on > that protocol to prevent the client from conforming to that protocol and > passing instances of other types my API wouldn’t want to deal with. That > creates unnecessary copies and I need to unpack the enum payload to find out > which type the user passed. Instead I could simply close the protocol, > wouldn’t need the requirement to exist and I could simply cast the type to > String or Int when needed. > > 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"]. > > Here is a list of hidden and semi-hidden protocols from the standard library > that could be closed. Formatted version: > https://gist.github.com/DevAndArtist/168c800d784829be536c407311953ab7 > <https://gist.github.com/DevAndArtist/168c800d784829be536c407311953ab7> > Path Protocol > /swift/stdlib/public/core/AnyHashable.swift:16 > _HasCustomAnyHashableRepresentation > /swift/stdlib/public/core/BidirectionalCollection.swift:21 > _BidirectionalIndexable > /swift/stdlib/public/core/BridgeObjectiveC.swift:19 _ObjectiveCBridgeable > /swift/stdlib/public/core/Collection.swift:20 _IndexableBase > /swift/stdlib/public/core/Collection.swift:176 _Indexable > /swift/stdlib/public/core/CompilerProtocols.swift:193 > _ExpressibleByBuiltinIntegerLiteral > /swift/stdlib/public/core/CompilerProtocols.swift:240 > _ExpressibleByBuiltinFloatLiteral > /swift/stdlib/public/core/CompilerProtocols.swift:283 > _ExpressibleByBuiltinBooleanLiteral > /swift/stdlib/public/core/CompilerProtocols.swift:316 > _ExpressibleByBuiltinUnicodeScalarLiteral > /swift/stdlib/public/core/CompilerProtocols.swift:350 > _ExpressibleByBuiltinExtendedGraphemeClusterLiteral > /swift/stdlib/public/core/CompilerProtocols.swift:398 > _ExpressibleByBuiltinStringLiteral > /swift/stdlib/public/core/CompilerProtocols.swift:407 > _ExpressibleByBuiltinUTF16StringLiteral > /swift/stdlib/public/core/CompilerProtocols.swift:670 > _ExpressibleByStringInterpolation > /swift/stdlib/public/core/CompilerProtocols.swift:709 > _ExpressibleByColorLiteral > /swift/stdlib/public/core/CompilerProtocols.swift:720 > _ExpressibleByImageLiteral > /swift/stdlib/public/core/CompilerProtocols.swift:730 > _ExpressibleByFileReferenceLiteral > /swift/stdlib/public/core/CompilerProtocols.swift:750 _DestructorSafeContainer > /swift/stdlib/public/core/FixedPoint.swift.gyb:53 _Integer > /swift/stdlib/public/core/FixedPoint.swift.gyb:70 _SignedInteger > /swift/stdlib/public/core/FixedPoint.swift.gyb:108 > _DisallowMixedSignArithmetic > /swift/stdlib/public/core/Hashable.swift:16 _Hashable > /swift/stdlib/public/core/Index.swift:16 _Incrementable > /swift/stdlib/public/core/IntegerArithmetic.swift.gyb:33 > _IntegerArithmetic > /swift/stdlib/public/core/Mirror.swift:721 > _DefaultCustomPlaygroundQuickLookable > /swift/stdlib/public/core/MutableCollection.swift:20 _MutableIndexable > /swift/stdlib/public/core/NewtypeWrapper.swift.gyb:16 _SwiftNewtypeWrapper > /swift/stdlib/public/core/Pointer.swift:16 _Pointer > /swift/stdlib/public/core/RandomAccessCollection.swift:20 > _RandomAccessIndexable > /swift/stdlib/public/core/RangeReplaceableCollection.swift.gyb:27 > _RangeReplaceableIndexable > /swift/stdlib/public/core/ReflectionLegacy.swift:41 _Mirror > /swift/stdlib/public/core/ShadowProtocols.swift:27 _ShadowProtocol > /swift/stdlib/public/core/ShadowProtocols.swift:31 _NSFastEnumeration > /swift/stdlib/public/core/ShadowProtocols.swift:41 _NSEnumerator > /swift/stdlib/public/core/ShadowProtocols.swift:51 _NSCopying > /swift/stdlib/public/core/ShadowProtocols.swift:61 _NSArrayCore > /swift/stdlib/public/core/ShadowProtocols.swift:83 _NSDictionaryCore > /swift/stdlib/public/core/ShadowProtocols.swift:125 _NSDictionary > /swift/stdlib/public/core/ShadowProtocols.swift:137 _NSSetCore > /swift/stdlib/public/core/ShadowProtocols.swift:171 _NSSet > /swift/stdlib/public/core/ShadowProtocols.swift:177 _NSNumber > /swift/stdlib/public/core/ShadowProtocols.swift:187 _NSArrayCore > /swift/stdlib/public/core/ShadowProtocols.swift:188 _NSDictionaryCore > /swift/stdlib/public/core/ShadowProtocols.swift:189 _NSSetCore > /swift/stdlib/public/core/StringBridge.swift:194 _NSStringCore > /swift/stdlib/public/SDK/Foundation/NSError.swift:353 > _ObjectiveCBridgeableError > /swift/stdlib/public/SDK/Foundation/NSError.swift:379 __BridgedNSError > /swift/stdlib/public/SDK/Foundation/NSError.swift:446 _BridgedNSError > /swift/stdlib/public/SDK/Foundation/NSError.swift:456 _BridgedStoredNSError > /swift/stdlib/public/SDK/Foundation/NSError.swift:564 _ErrorCodeProtocol > > > > -- > Adrian Zubarev > Sent with Airmail > > Am 19. Februar 2017 um 07:59:45, David Waite via swift-evolution > (swift-evolution@swift.org <mailto:swift-evolution@swift.org>) schrieb: > >> 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? >> >> 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 <mailto:swift-evolution@swift.org> >> https://lists.swift.org/mailman/listinfo/swift-evolution >> <https://lists.swift.org/mailman/listinfo/swift-evolution> >
_______________________________________________ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution