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

Reply via email to