[swift-evolution] [Review #2] SE-0161: Smart KeyPaths: Better Key-Value Coding for Swift

Joe Groff jgroff at apple.com
Fri Apr 7 14:04:35 CDT 2017


> On Apr 7, 2017, at 12:01 PM, John McCall <rjmccall at apple.com> wrote:
> 
>> 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.

Yeah, the restrictions on overloading properties are effectively superficial, since protocol extensions and library evolution still give you means to end up with an overloaded property name. Subscripts are already arbitrarily overloadable.

-Joe


More information about the swift-evolution mailing list