[swift-evolution] [Pitch] Improving KeyPath
Joe Groff
jgroff at apple.com
Fri Aug 25 13:43:08 CDT 2017
> On Aug 23, 2017, at 11:18 PM, Logan Shire via swift-evolution <swift-evolution at swift.org> wrote:
>
> Hey folks!
>
> Recently I’ve been working on a small library which leverages the Swift 4 Codable protocol
> and KeyPaths to provide a Swift-y interface to CoreData. (It maps back and forth between
> native, immutable Swift structs and NSManagedObjects). In doing so I found a couple of
> frustrating limitations to the KeyPath API. Firstly, KeyPath does not provide the name of the
> property on the type it indexes. For example, if I have a struct:
>
>
> struct Person {
> let firstName: String
> let lastName: String
> }
>
> let keyPath = \Person.firstName
>
>
> But once I have a keyPath, I can’t actually figure out what property it accesses.
> So, I wind up having to make a wrapper:
>
>
> struct Attribute {
> let keyPath: AnyKeyPath
> let propertyName: String
> }
>
> let firstNameAttribute = Attribute(keyPath: \Person.firstName, propertyName: “firstName”)
>
>
> This forces me to write out the property name myself as a string which is very error prone.
> All I want is to be able to access:
>
>
> keyPath.propertyName // “firstName”
>
>
> It would also be nice if we provided the full path as a string as well:
>
>
> keyPath.fullPath // “Person.firstName"
>
>
> Also, if I want to get all of the attributes from a given Swift type, my options are to try to hack
> something together with Mirrors, or forcing the type to declare a function / computed property
> returning an array of all of its key path / property name pairings. I would really like to be able to
> retrieve a type-erased array of any type’s key paths with:
>
>
> let person = Person(firstName: “John”, lastName: “Doe”)
> let keyPaths = Person.keyPaths
> let firstNameKeyPath = keyPaths.first { $0.propertyName = “firstName” } as! KeyPath<Person, String>
> let firstName = person[keypath: firstNameKeyPath] // “John"
>
>
> And finally, without straying too far into Objective-C land, it would be nice if we could initialize key paths
> with a throwing initializer.
>
>
> let keyPath = try Person.keyPath(“firstName”) // KeyPath<Person, String> type erased to AnyKeyPath
> let keyPath = AnyKeyPath(“Person.firstName”)
>
>
> Let me know what you think about any / all of these suggestions!
These would all be great additional features to eventually add to key paths. I think reflection mechanisms centered on key paths like what you describe would be a superior replacement for most of what Mirror attempts to provide.
-Joe
More information about the swift-evolution
mailing list