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