[swift-evolution] [Review #2] SE-0161: Smart KeyPaths: Better Key-Value Coding for Swift
John McCall
rjmccall at apple.com
Fri Apr 7 14:01:27 CDT 2017
> On Apr 7, 2017, at 2:50 PM, Joe Groff <jgroff at apple.com> wrote:
>> On Apr 7, 2017, at 11:48 AM, John McCall <rjmccall at apple.com> wrote:
>>
>>> On Apr 7, 2017, at 1:40 PM, Joe Groff <jgroff at apple.com> wrote:
>>>> On Apr 7, 2017, at 10:20 AM, John McCall via swift-evolution <swift-evolution at swift.org> wrote:
>>>>
>>>>>
>>>>> On Apr 7, 2017, at 12:48 AM, Douglas Gregor <dgregor at apple.com> wrote:
>>>>>
>>>>>
>>>>>> On Apr 6, 2017, at 9:46 PM, John McCall <rjmccall at apple.com> wrote:
>>>>>>
>>>>>>> On Apr 7, 2017, at 12:27 AM, Rick Mann <rmann at latencyzero.com> wrote:
>>>>>>>> On Apr 6, 2017, at 20:37 , John McCall <rjmccall at apple.com> wrote:
>>>>>>>>
>>>>>>>>> On Apr 6, 2017, at 9:28 PM, Rick Mann via swift-evolution <swift-evolution at swift.org> wrote:
>>>>>>>>> I tend to dislike the backslash as well, but can't suggest a good alternative.
>>>>>>>>>
>>>>>>>>> Does any of this allow for operations within the key path? e.g. Department.employees. at sum.salary?
>>>>>>>>
>>>>>>>> You can express things like this in the feature as proposed using subscripts:
>>>>>>>>
>>>>>>>> extension Collection {
>>>>>>>> subscript<T: Integer>(summing path: KeyPath<Element, T>) -> T {
>>>>>>>> var sum: T = 0
>>>>>>>> for let elt in self {
>>>>>>>> sum += elt[keyPath: path]
>>>>>>>> }
>>>>>>>> return sum
>>>>>>>> }
>>>>>>>> }
>>>>>>>
>>>>>>> I'm just remembering how AppKit/Cocoa lets you do things like this in a very expressive way. Your proposal seems a bit cumbersome. Maybe when we have custom annotations, they can be extended to use within key paths.
>>>>>>
>>>>>> I'm not seriously endorsing this exact spelling. It would be much better to be able to write something like:
>>>>>> \Department.employees.sum(of: \.salary)
>>>>>> However, since "sum" would presumably be a method on Collection, I think this would have to be a future extension to the proposal, and the overall thing might have to be a function rather than a key path because it would no longer have identity.
>>>>>
>>>>> Also, less clever but potentially easier to reason about:
>>>>>
>>>>> extension Array where Element == Employee {
>>>>> var sumOfSalary: Double {
>>>>> return // ...
>>>>> }
>>>>> }
>>>>>
>>>>> If you can express it in a computed property, you can refer to it via a key path:
>>>>>
>>>>> \Department.employees.sumOfSalary
>>>>
>>>> Yeah, you can, but that's definitely an expressivity hit.
>>>
>>> True, but there are some benefits to requiring a subscript/property rather than an arbitrary closure, particularly that it gives the operation a stable identity and structure so the key path can still be equated/hashed and (eventually) iterated through.
>>
>> Right, I think if you add a method to the chain, the result definitely has to be a function rather than a key path. The idea is that you basically decompose:
>>
>> \Base.A.B.C
>>
>> into
>> ([inout]? Base, parameters(A)..., parameters(B)..., parameters(C)...) -> result(C)
>>
>> except that if all of the components A, B, and C are just properties or applied subscripts you can make it a KeyPath<Base,C> instead, which can then contextually devolve into a function.
>
> It seems to me that method references (non-mutating ones, at least) could still be treated as read-only key path components. There's not much more than syntax as a difference between a nonmutating method and get-only property or subscript. The method decl is still something we can ascribe identity to.
That's true. My concern with ascribing identity to methods is that we have a number of features around methods — overloading, default arguments, various kinds of polymorphism — that make the exact choice of declaration somewhat imprecise. Should it be a different key path if we pick a protocol requirement vs. a concrete method that satisfies it? I suppose we have that specific problem with properties and subscripts as well, though.
John.
More information about the swift-evolution
mailing list