SE-0062 Referencing Objective-C key-paths


(Les Pruszynski) #1

This is my first post on this list so please bear with me.

I very much like this proposal but what bothers me is this doubling of valueForKeyPath(#keyPath(xxx) in the signature of the function.

chris.valueForKeyPath(#keyPath(Person.bestFriend.lastName)) // => Groff
chris.valueForKeyPath(#keyPath(Person.friends.firstName)) // => ["Joe", "Douglas"]

I’m not sure whether the form below is actually possible. For me it reads more naturally and is more consistent with “Modern Swift” as far as I know.

chris.valueFor(#keyPath(Person.friends.firstName)) // => ["Joe", "Douglas”]
or maybe
chris.valueOf(#keyPath(Person.friends.firstName)) // => ["Joe", "Douglas”]

Just my observation.
Regards


(Brent Royal-Gordon) #2

I very much like this proposal but what bothers me is this doubling of valueForKeyPath(#keyPath(xxx) in the signature of the function.

chris.valueForKeyPath(#keyPath(Person.bestFriend.lastName)) // => Groff

chris
.valueForKeyPath(#keyPath(Person.friends.firstName)) // => ["Joe", "Douglas"]

I’m not sure whether the form below is actually possible. For me it reads more naturally and is more consistent with “Modern Swift” as far as I know.

chris.valueFor(#keyPath(Person.friends.firstName)) // => ["Joe", "Douglas”]
or maybe
chris.valueOf(#keyPath(Person.friends.firstName)) // => ["Joe", "Douglas”]

Interesting.

If Foundation, Core Data, AppKit, and other frameworks properly annotated their APIs, I think we could actually get this from the already accepted SE-0033 "Import Objective-C Constants as Swift Types" <https://github.com/apple/swift-evolution/blob/master/proposals/0033-import-objc-constants.md>. Specifically, Foundation would have to include this typedef:

  typedef NSString * NSKeyPath __attribute__((swift_wrapper(struct)));

And all APIs with string types which were actually key paths would have to be modified to use it. Then `-(nullable id)valueForKeyPath:(NSKeyPath)keyPath` would import as `func value(for: NSKeyPath) -> AnyObject?`. This proposal's `#keyPath` construct would have to then construct an `NSKeyPath` instead of a `String`.

(To make this all work, it might make sense to add a KeyPathLiteralConvertible protocol to the standard library. As a bonus, if this protocol's initializer received enough metadata, it might be able to construct alternate forms of key paths, such as the Rails-style ones which handle arrays somewhat differently from Foundation's.)

This is more work, but it's also more general, which is a pretty cool prospect!

···

--
Brent Royal-Gordon
Architechies


(Douglas Gregor) #3

If key paths were some stronger type (as Brent is suggesting), we could do this. However, because key paths are just Strings, we need to compensate for weak type information <https://swift.org/documentation/api-design-guidelines/#promote-clear-usage>, so valueForKeyPath should retain it’s currently name despite the redundancy in many use sites with #keyPath.

  - Doug

···

On Apr 7, 2016, at 9:34 PM, Les Pruszynski via swift-evolution <swift-evolution@swift.org> wrote:

This is my first post on this list so please bear with me.

I very much like this proposal but what bothers me is this doubling of valueForKeyPath(#keyPath(xxx) in the signature of the function.

chris.valueForKeyPath(#keyPath(Person.bestFriend.lastName)) // => Groff
chris.valueForKeyPath(#keyPath(Person.friends.firstName)) // => ["Joe", "Douglas"]

I’m not sure whether the form below is actually possible. For me it reads more naturally and is more consistent with “Modern Swift” as far as I know.

chris.valueFor(#keyPath(Person.friends.firstName)) // => ["Joe", "Douglas”]
or maybe
chris.valueOf(#keyPath(Person.friends.firstName)) // => ["Joe", "Douglas”]


(Christian Kienle) #4

Key-Paths do support operators and custom functions. How should this work
within the context of this proposal?

···

2016-04-12 11:14 GMT+02:00 Brent Royal-Gordon via swift-evolution < swift-evolution@swift.org>:

> I very much like this proposal but what bothers me is this doubling of
valueForKeyPath(#keyPath(xxx) in the signature of the function.
>
> chris.valueForKeyPath(#keyPath(Person.bestFriend.lastName)) // => Groff
>
> chris
> .valueForKeyPath(#keyPath(Person.friends.firstName)) // => ["Joe",
"Douglas"]
>
> I’m not sure whether the form below is actually possible. For me it
reads more naturally and is more consistent with “Modern Swift” as far as I
know.
>
> chris.valueFor(#keyPath(Person.friends.firstName)) // => ["Joe",
"Douglas”]
> or maybe
> chris.valueOf(#keyPath(Person.friends.firstName)) // => ["Joe",
"Douglas”]

Interesting.

If Foundation, Core Data, AppKit, and other frameworks properly annotated
their APIs, I think we could actually get this from the already accepted
SE-0033 "Import Objective-C Constants as Swift Types" <
https://github.com/apple/swift-evolution/blob/master/proposals/0033-import-objc-constants.md>.
Specifically, Foundation would have to include this typedef:

        typedef NSString * NSKeyPath
__attribute__((swift_wrapper(struct)));

And all APIs with string types which were actually key paths would have to
be modified to use it. Then `-(nullable
id)valueForKeyPath:(NSKeyPath)keyPath` would import as `func value(for:
NSKeyPath) -> AnyObject?`. This proposal's `#keyPath` construct would have
to then construct an `NSKeyPath` instead of a `String`.

(To make this all work, it might make sense to add a
KeyPathLiteralConvertible protocol to the standard library. As a bonus, if
this protocol's initializer received enough metadata, it might be able to
construct alternate forms of key paths, such as the Rails-style ones which
handle arrays somewhat differently from Foundation's.)

This is more work, but it's also more general, which is a pretty cool
prospect!

--
Brent Royal-Gordon
Architechies

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

--
Mit freundlichen Grüßen

*Christian Kienle*
Mobile Developer

*REWE Digital GmbH*
Domstraße 20, 50668 Köln, Büro: Schanzenstr. 6-20, 51063 Köln
Geschäftsführer: Dr. Jean-Jacques Michel van Oosten (Vorsitzender),
Christoph Eltze, Dr. Johannes Steegmann, Dr. Robert Zores
Handelsregister: Amtsgericht Köln (HRB 78670) UST-ID-Nr.: DE 290 605 450

Telefon: +49 151 11441782
E-Mail: christian.kienle@rewe-digital.com
Internet: *www.rewe-digital.com <http://www.rewe-digital.com/>*

Ein Unternehmen der *REWE GROUP*
http://www.rewe-group.com


(Kenny Leung) #5

Hi All.

Aeons ago, I was on the team that invented key paths. There were some pretty major performance issues:

- the key path had to be separated into its individual components, requiring processing time and generating a bunch of garbage

- the obvious thing to do would have been to parse the key path into an array of strings up front, and then simply process the key path in a loop, but this was not possible because some objects might override valueForKeyPath and be expecting to parse their own portion of the key path (and down) in some special way

- pre-parsing may also be problematic because key paths could contain operators like @count, or @sum, @avg, etc.

That being said, it would certainly be nice if the compiler pre-parsed key paths into either:
- key path objects
- arrays of strings
- arrays of “key” objects

and KVC was modified to accept these as a lower level API.

Perhaps it would be prudent to pull in the Foundation guys on this and get their input before implementing something on the Swift side that would be hard to take back.

-Kenny

···

On Apr 12, 2016, at 9:35 AM, Douglas Gregor via swift-evolution <swift-evolution@swift.org> wrote:

On Apr 7, 2016, at 9:34 PM, Les Pruszynski via swift-evolution <swift-evolution@swift.org> wrote:

This is my first post on this list so please bear with me.

I very much like this proposal but what bothers me is this doubling of valueForKeyPath(#keyPath(xxx) in the signature of the function.

chris.valueForKeyPath(#keyPath(Person.bestFriend.lastName)) // => Groff

chris
.valueForKeyPath(#keyPath(Person.friends.firstName)) // => ["Joe", "Douglas"]

I’m not sure whether the form below is actually possible. For me it reads more naturally and is more consistent with “Modern Swift” as far as I know.

chris.valueFor(#keyPath(Person.friends.firstName)) // => ["Joe", "Douglas”]
or maybe
chris.valueOf(#keyPath(Person.friends.firstName)) // => ["Joe", "Douglas”]

If key paths were some stronger type (as Brent is suggesting), we could do this. However, because key paths are just Strings, we need to compensate for weak type information, so valueForKeyPath should retain it’s currently name despite the redundancy in many use sites with #keyPath.

  - Doug

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution