Sent from my iPad

> On Feb 19, 2017, at 11:29 AM, David Waite via swift-evolution 
> <swift-evolution@swift.org> wrote:
> 
> 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”]

Can you make this work with variables - not just literals - and still prevent 
users from extending the set of types and without requiring an enum case 
constructor to be used by clients?


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