You’re right on the specifics, of course.

To be clear I am more concerned about accidental shadowing with such 
subscripts; picture starting initial development with only the generic 
subscript from the proposal, writing some code that uses it…and then at some 
later point in time importing a module that defines the `RawRepresentable` 
variant, which would subtly shift how your code got interpreted.

This isn’t anything that couldn’t happen today with plain-old functions, of 
course — and it can be worked around in various ways, if you know it happens — 
but given the IMHO much higher likelihood of "name collisions” (you’re correct 
you can label the subscript arguments, but I doubt most subscripts will opt to 
do so)…it seems far likelier we’ll see resolution-modifying collisions under a 
proposal like this, should it be introduced.

But I could be very wrong, and in any case this proposal should probably wait 
until at least August, as per suggestion.

> On Jun 22, 2016, at 9:29 AM, Matthew Johnson <matt...@anandabits.com> wrote:
> 
>> 
>> On Jun 22, 2016, at 9:11 AM, plx via swift-evolution 
>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>> 
>> 
>>> On Jun 22, 2016, at 8:28 AM, T.J. Usiyan <griotsp...@gmail.com 
>>> <mailto:griotsp...@gmail.com>> wrote:
>>> 
>>> plx: wouldn't the same overload resolution strategy be appropriate here? 
>>> "most specific choice, otherwise diagnostic”
>> 
>> I’d assume it’d be good enough for most cases, certainly; I’d love to turn 
>> out to be needlessly scaremongering here, too.
>> 
>> But (hopefully unintentionally!) it seems like you could easily wind up with 
>> scenarios like this:
>> 
>>   // from proposal:
>>   public subscript<T>(key: Key) throws -> T {
>>     guard let value = self[key] else { throw ... }
>>     guard let ofType = value as? T else { throw ... }
>>     return ofType
>>   }
>> 
>>   // an annoying addition:
>>   public subscript<T:RawRepresentable>(key: Key) throws -> T {
>>     guard let v = self[key] else { throw ... }
>>     guard let rawValue = v as? T.RawValue else { throw ... }
>>     guard let converted = T(rawValue: rawValue) else { throw ... }
>>     return converted
>>   }
>> 
>>   // assume `Foo:RawRepresentable`:
>>   let foo: Foo = json["foo"]
>> 
>> …and similar, where I’d assume the `T:RawRepresentable` would “win”, but I’m 
>> not sure *how* you could force use of the *other* subscript in the above.
>> 
>> This isn’t really a new problem, but it seems likelier to be encountered if 
>> generic subscripts become allowed, due to all subscripts having the same 
>> “name”.
> 
> This isn’t exactly true.  External argument labels are considered part of the 
> “name” in Swift.  Subscripts parameters don’t get external labels 
> automatically like other functions / methods do, but you can still add one if 
> you *want* the ability to disambiguate.  
> 
> Of course this won’t help if you require the ability to use both subscripts 
> without a label but is worth noting.  It is also worth noting that this 
> behavior is no different from that of any other function or method - if the 
> name (including external argument labels) matches the most specific overload 
> will always be selected.
> 
> One way to make your example work properly when `T` is `RawRepresentable` and 
> the dictionary actually contains an instance of `T` is to add an extra check 
> for that case:
> 
>   public subscript<T:RawRepresentable>(key: Key) throws -> T {
>     guard let v = self[key] else { throw … }
> 
>     // extra check here in case the value is *already* T and therefore does 
> not require conversion.
>     if let value = v as? T { return value }
> 
>     guard let rawValue = v as? T.RawValue else { throw ... }
>     guard let converted = T(rawValue: rawValue) else { throw ... }
>     return converted
>   }
> 
>> 
>> But again I’d like to be wrong about the issue (or at least the severity).
>> 
>>> 
>>> separately:
>>> Are there any subscripts in the standard library that would be 
>>> throwing/generic but can't be?
>>> 
>>> 
>>> On Wed, Jun 22, 2016 at 9:13 AM, plx via swift-evolution 
>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>> Prefacing the below with a “I am well-aware this proposal likely won’t make 
>>> it into Swift 3”:
>>> 
>>> A feature like this would be nice to use, but before I could get behind any 
>>> proposal along these lines it I’d want to see it include an explicit 
>>> strategy for disambiguation.
>>> 
>>> EG: in your example, your generic subscript uses `self[key]`, and 
>>> presumably expects that to use the “original” subscript…and not the generic 
>>> subscript being defined.
>>> 
>>> I think that’s reasonable in that specific case, but it doesn’t seem 
>>> unreasonable to anticipate this proposal introducing ambiguities that would 
>>> need explicit disambiguation…and for which explicit type annotation may not 
>>> always be adequate to resolve (I could be wrong here, though). 
>>> 
>>> This would need addressing (either showing they won’t be an issue, or 
>>> providing a reliable disambiguation mechanism).
>>> 
>>> Relatedly, in-re: “rethrows”: if the syntax supported it, this kind of 
>>> thing would be another way of tackling the "JSON problem":
>>> 
>>>   subscript<T>(key: Key, transform: (Value) throws -> T) rethrows -> T {
>>>     guard let value = self[key] else { throw JSON.MissingKey(…) }
>>>     return try transform(value)
>>>   }
>>> 
>>> …so that e.g. you can write typical parsing-code as
>>> 
>>>   let asUserID = UserID.init(untrustedString:) // <- assume this is a 
>>> "throwing constructor"
>>>   let sender = try json[“sender”,asUserID] 
>>>   let recipient = try json[“recipient”,asUserID]
>>> 
>>> …(modulo any syntax errors, etc.), which would benefit from a `rethrows` 
>>> declaration.
>>> 
>>> That’s my 2c; thankfully (IMHO) there’s clearly a lot of time for this 
>>> proposal to simmer.
>>> 
>>>> On Jun 20, 2016, at 1:10 PM, Robert Widmann via swift-evolution 
>>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>>> 
>>>> Good morning all.  Attached is the proposal Harlan Haskins and I will be 
>>>> submitting shortly about adding generic and `throw`ing subscript 
>>>> declarations to the language.  
>>>> 
>>>> Cheers,
>>>> 
>>>> ~Robert Widmann
>>>> 
>>>> Generic and Throwing Subscripts
>>>> 
>>>> Proposal: SE-NNNN 
>>>> <https://github.com/apple/swift-evolution/blob/master/proposals/NNNN-name.md>
>>>> Author(s): Harlan Haskins <https://github.com/harlanhaskins> and Robert 
>>>> Widmann <https://github.com/codafi>
>>>> Status: Awaiting review 
>>>> <https://github.com/typelift/SwiftCheck/pull/168#rationale>
>>>> Review manager: TBD
>>>> Introduction
>>>> 
>>>> Currently, subscripts cannot be declared [re]throws and cannot declare new 
>>>> generic parameters.
>>>> There isn't a clear reason why they aren't as capable as full-fledged 
>>>> functions, so we propose
>>>> adding generic constraints and throwing semantics to subscripts.
>>>> 
>>>> Motivation
>>>> 
>>>> On the throwing side, currently there are two ways to express a failing 
>>>> subscript:
>>>> 
>>>> Return an Optional, failing with nil.
>>>> Call fatalError(_:) on failure.
>>>> Both of these throw out useful information about the cause of the 
>>>> underlying error that using Swift's error handling mechanism can otherwise 
>>>> provide.
>>>> 
>>>> As for generics, to take an example, it has become a common pattern among 
>>>> JSON decoding DSL libraries to express a throwing generic extension on 
>>>> Dictionary like so
>>>> 
>>>> extension Dictionary {
>>>>     public func parse<T>(key: Key) throws -> T {
>>>>         guard let value = self[key] else {
>>>>             throw JSONError.MissingKey("\(key)")
>>>>         }
>>>>         guard let ofType = value as? T else {
>>>>             throw JSONError.InvalidKey(key: "\(key)", expectedType: 
>>>> T.self, foundType: value.dynamicType)
>>>>         }
>>>>         return ofType
>>>>     }
>>>> }
>>>> 
>>>> public enum JSONError: ErrorType, CustomStringConvertible {
>>>>     case InvalidKey(key: String, expectedType: Any.Type, foundType: 
>>>> Any.Type)
>>>>     case MissingKey(String)
>>>>     public var description: String {
>>>>         switch self {
>>>>         case .InvalidKey(let key, let expected, let found):
>>>>             return "Invalid key \"\(key)\". Expected value of type 
>>>> \"\(expected)\", found \"\(found)\"."
>>>>         case .MissingKey(let key):
>>>>             return "Key \(key) not found."
>>>>         }
>>>>     }
>>>> }
>>>> Given this, one can decode JSON with the full support of native type 
>>>> inference and exception handling. But when working with the DSL, one would 
>>>> expect to be able to express this as a subscript on Dictionary, allowing 
>>>> the following:
>>>> 
>>>> //...
>>>> 
>>>> extension Dictionary {
>>>>     public subscript<T>(key: Key) throws -> T {
>>>>         guard let value = self[key] else {
>>>>             throw JSONError.MissingKey("\(key)")
>>>>         }
>>>>         guard let ofType = value as? T else {
>>>>             throw JSONError.InvalidKey(key: "\(key)", expectedType: 
>>>> T.self, foundType: value.dynamicType)
>>>>         }
>>>>         return ofType
>>>>     }
>>>> }
>>>> We believe this is an even more natural way to write these kinds of 
>>>> libraries in Swift and that bringing subscript member declarations up to 
>>>> par with functions is a useful addition to the language as a whole.
>>>> 
>>>> Proposed solution
>>>> 
>>>> Add the ability to introduce new generic parameters and mark throws and 
>>>> rethrows on subscript members.
>>>> 
>>>> Detailed design
>>>> 
>>>> This change will modify and add the following productions in the Swift 
>>>> grammar
>>>> 
>>>> GRAMMAR OF A SUBSCRIPT DECLARATION
>>>> 
>>>> subscript-declaration → subscript-head subscript-result code-block
>>>> subscript-declaration → subscript-head subscript-result getter-setter-block
>>>> subscript-declaration → subscript-head subscript-result 
>>>> getter-setter-keyword-block
>>>> -subscript-head → attributes(opt) declaration-modifiers(opt) subscript 
>>>> parameter-clause
>>>> +subscript-head → attributes(opt) declaration-modifiers(opt) 
>>>> generic-parameter-clause(opt) subscript parameter-clause
>>>> +subscript-result → -> attributes(opt) throws(opt) type
>>>> +subscript-result → -> attributes(opt) rethrows(opt) type
>>>> Rationale
>>>> 
>>>> On [Date], the core team decided to (TBD) this proposal.
>>>> When the core team makes a decision regarding this proposal,
>>>> their rationale for the decision will be written here.
>>>> _______________________________________________
>>>> 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 <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 <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