[swift-evolution] Smart KeyPaths
Matthew Johnson
matthew at anandabits.com
Wed Mar 29 20:08:47 CDT 2017
Sent from my iPad
> On Mar 29, 2017, at 7:32 PM, Joe Groff via swift-evolution <swift-evolution at swift.org> wrote:
>
>
>> On Mar 29, 2017, at 5:29 PM, Michael J LeHew Jr <lehewjr at apple.com> wrote:
>>
>>
>>>> On Mar 29, 2017, at 4:52 PM, Brent Royal-Gordon <brent at architechies.com> wrote:
>>>>
>>>> On Mar 29, 2017, at 4:13 PM, Michael J LeHew Jr via swift-evolution <swift-evolution at swift.org> wrote:
>>>>
>>>> Thanks for the feedback everyone! We have pushed a changed a bit ago to the proposal reflecting these desires.
>>>>
>>>> https://github.com/apple/swift-evolution/pull/644/files
>>>
>>> Quoting from the proposal:
>>>
>>>> luke[keyPath: #keyPath(.friends[0].name)]
>>>
>>> Really? I can understand marking one or the other, but both, even when there's no ambiguity?
>>
>> I had the same reaction initially -- but then after talking with Joe, he reminded me that this is the kind of code that only comes up in a 'this is how it works' context. Typically the key path will be a value and the syntax looks like: luke[keyPath: somePath]
>>
>> That example is a touch contrived to show that we'll be able to do the type inference where possible,
>>
>>>
>>> Let's pretend we're the type checker here. The `luke[keyPath: _]` part will create a context where we know we have an `AnyKeyPath`, `PartialKeyPath<Person>`, `KeyPath<Person, U>`, or `WritableKeyPath<Person, U>`. So if the core team's concern is about namespace clashes between `Person`'s static members and key paths, why not hang the key paths off the various `KeyPath` types? That is, this:
>>>
>>> struct Person {
>>> var friends: [Person]
>>> var name: String
>>> }
>>>
>>> Implies this:
>>>
>>> extension PartialKeyPath where Root == Person {
>>> static let friends: WritableKeyPath<Person, [Person]>
>>> static let name: WritableKeyPath<Person, String>
>>> }
>>>
>>> And this:
>>>
>>> #keyPath(Person, .friends[0].name)
>>>
>>> Desugars to this:
>>>
>>> PartialKeyPath<Person>.friends[0].name
>>>
>>> So in a context where you already know you're passing a key path, you can simply write this:
>>>
>>> luke[keyPath: .friends[0].name]
>>>
>>> Which applies normal "unresolved member" logic to look it up in `PartialKeyPath`.
>>>
>>> The result would be that you would have to explicitly, syntactically mark key paths except when the context already implied you were looking for one. In an unconstrained generic context, you would not get a key path without using `#keyPath` or explicitly naming a key path type. You would only need to worry about clashes if a call was overloaded to accept *both* `T` and `PartialKeyPath<T>`; if we found that possibility troubling, we could penalize unresolved member lookups that resolve to key paths, so type inference would favor static members over key paths even in those cases.
>>>
>>> Would that work for people?
>>
>> I'll let Joe speak to this aspect since this touches a lot more on implementation.
>
> Yes, that could work, and that's in fact what was proposed in the first draft. The core team is reasonably hesitant to give up syntactic real estate up front without more evidence that this feature is pervasive enough to deserve it. I think keypaths are useful enough that they certainly could be, but it's easier to add more compact syntax later than to take it away.
The one big loss I see from the original proposal is that the current design does not allow us to create a type context that provides something as concise as the original dot shorthand to create key paths. It's still supported in one sense, but require the #keyPath() wrapper around the key path expression. That's a lot less elegant.
I would love it if we found a way to retain something as concise as that shorthand. I'm working on a library where users will specify a collection of key paths pairs. This shorthand would be a very nice piece of sugar making the code expressing these collections (usually literals) quite a bit more readable.
>
> -Joe
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
More information about the swift-evolution
mailing list