On Wed, Jun 22, 2016 at 9:13 AM, plx via swift-evolution < 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> 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
https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution