I’m polite but I don’t see why every single piece is questioned with “why”.

Your example is exactly the workaround I presented in first place. Interesting 
right? But it still fails the challenge, because the set of types can be 
extended by the client, however at least with this there won’t be any runtime 
crashes in Swift 3.X.



-- 
Adrian Zubarev
Sent with Airmail

Am 20. Februar 2017 um 00:14:28, David Hart (da...@hartbit.com) schrieb:


On 20 Feb 2017, at 00:10, Adrian Zubarev via swift-evolution 
<swift-evolution@swift.org> wrote:

Because someInstance["key", .string("key1"), .integer(1), 
.string(stringKeyInstance), .integer(intIndexInstance), 
.integer(intIndexInstance), …] is simply ugly and should be hidden. Such API 
looks horrible.

Is this discussion really going to end with every statement being questioned 
with “why”? Why is 42 the number that rules the universe?

Lets stay polite and keep things civil.

The "the client should not be able to extend the set of types you can pass to 
that subscript.” requirement seems totally arbitrary and an anti-pattern. I’m 
perfectly happy with:

enum Key {
    case string(String)
    case int(Int)
}

protocol KeyConvertible {
    var key: Key { get }
}

subscript(initial: String, others: KeyConvertible...) -> Foo

-- 
Adrian Zubarev
Sent with Airmail

Am 20. Februar 2017 um 00:03:44, Xiaodi Wu (xiaodi...@gmail.com) schrieb:

On Sun, Feb 19, 2017 at 4:51 PM, Adrian Zubarev 
<adrian.zuba...@devandartist.com> wrote:
Matthew has pretty much summed up everything with a single question in his last 
reply. It makes me tired of repeating myself over and over again.

Here’s the challenge for you:

Implement a subscript where the first parameter is a String (trivial), but the 
second to n are String’s and/or Int’s. There is no restriction of order for the 
Int’s and String’s and there could be as many as you’d like, so no overloads 
are allowed (a hint: variadics). You should be able to use variables in that 
subscript and literals. You’re not allowed to use enum constructors

Why not? You want a parameter that takes either String or Int. In another 
language, you might express this as `String | Int`, but Chris Lattner and 
others have said on this list that enums are the intended way of expressing 
this in Swift.
and the client should not be able to extend the set of types you can pass to 
that subscript. That said it can look like this: someInstance["key", "key1", 1, 
stringKeyInstance, intIndexInstance, intIndexInstance, …]

Creating hacks like unreachable types with hidden inits is prohibited.

Have fun!



-- 
Adrian Zubarev
Sent with Airmail

Am 19. Februar 2017 um 23:25:11, Xiaodi Wu (xiaodi...@gmail.com) schrieb:

Sorry, I have read through this thread twice and do not understand the point 
you are making. Can you explain your example once more?

Specifically, I do not understand why it is that your code should have problems 
with third-party types that conform to your protocol. If your protocol has 
requirements that third-party types cannot fulfill, then naturally those 
requirements will prevent a third-party from conforming new types to your 
protocol. OTOH, if your protocol does not have any requirements that 
third-party types cannot fulfill, then your code that accepts anything that 
conforms to your protocol should be indifferent to whether the conforming type 
is defined by you or someone else. After all, a conforming type would fulfill 
all the semantic and syntactic requirements of the protocol! If your protocol 
has requirements that you are unable to state in code, causing third-party 
types to conform that really shouldn't, then that is a case for additional 
features that allow you to express those requirements more accurately, not an 
argument for having protocols that can't be conformed to by a third-party. What 
am I missing?


On Sun, Feb 19, 2017 at 11:53 AM, Adrian Zubarev via swift-evolution 
<swift-evolution@swift.org> wrote:
That’s the whole point I was making. :) Thank you Matthew. That makes my 
example a real world example and not just some bike shedding.

-- 
Adrian Zubarev
Sent with Airmail

Am 19. Februar 2017 um 18:50:31, Matthew Johnson (matt...@anandabits.com) 
schrieb:



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




_______________________________________________
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