[swift-evolution] [Review] SE-0062: Referencing Objective-C key-paths

Brent Royal-Gordon brent at architechies.com
Thu Apr 7 23:23:51 CDT 2016


> https://github.com/apple/swift-evolution/blob/master/proposals/0062-objc-keypaths.md

> 	• What is your evaluation of the proposal?

I'm definitely in favor and look forward to using #keyPath. I have one note, one suggestion and one concern, but even without any of them being addressed, I would want to see this proposal become part of Swift.

* * *

The note: The Collection crossing might apply only to types which offer `Index -> Element` and `Range<Index> -> SubSequence` subscripts, but no others. That would include Array and Set but exclude Dictionary.

On the other hand, NSDictionary *does* have KVC behavior: the particular key is unconstrained and it always results in an instance of the dictionary's ObjectType. #keyPath could usefully support that in some way.

* * *

The suggestion: Many key paths are immediately passed to methods on the object they will eventually act on. For example:

	chris.value(forKeyPath: #keyPath(Person.friends.firstName))

It would be nice if we could use leading dot to refer to the type of the object the key path is being passed to:

	chris.value(forKeyPath: #keyPath(.friends.firstName))

Leading dot does not have any other useful meaning in this context; it would always refer to a static variable on String, which is not a sensible key path to try to construct.

* * *

The concern: I'm a little worried that the "value expression" feature can be ambiguous when accessing properties of `self`. Consider these expressions (as they might appear in the `Person.find(name:)` example):

	#keyPath(firstName.uppercased)	=> "firstName.uppercased"
	#keyPath(name.uppercased)		=> "uppercased"

Although they look quite similar, they end up giving very different behaviors because `firstName` is a property while `name` is a variable. I think this could be misleading—particularly because it'll be tempting to say things like this:

	firstName.value(forKeyPath: #keyPath(firstName.uppercased))	// oops, that's getting `self.firstName.firstName.uppercased`!

I see two simple but inconsistent alternatives here, and one which is more complex but also more consistent:

1. Require `self` for a property's key path. This makes it clear that you're going to get "firstName.uppercased", but it's a little inconvenient in the plain `firstName` case, which isn't ambiguous.

2. Require `self` for a property's key path only when there are additional parts to the key path. In other words, you can say `#keyPath(firstName)`, but firstName.uppercased's keypath has to be written `#keyPath(self.firstName.uppercased)`. This removes the inconvenience of #1, but it's a complicated rule to explain.

3. Change the syntax entirely so that the thing you're looking for the key path of goes before the #keyPath keyword. This would make it crystal clear which part is the key path and which part merely specifies the type the key path will be used on; it would also allow you to use a more complicated expression to provide the type. Examples:

	Person.#keyPath(firstName.uppercased)
	self.#keyPath(firstName.uppercased)
	#keyPath(firstName.uppercased)	// Implicit `self`
	
	// Here's an example of a complicated path to the object you want to work from
	textView.layoutManager.typesetter.#keyPath(usesFontLeading)
	
	// The leading dot feature I asked for would look like:
	chris.value(forKeyPath: .#keyPath(friends.firstName))

This looks weird when you're not used to it, but it's not really that strange an idea conceptually; if #foo() is a compile-time function, this is a compile-time method.

* * *

Despite these concerns, I really like this proposal a lot, and I hope to see it be accepted.

> 	• Is the problem being addressed significant enough to warrant a change to Swift?

Yes. Simply put, stringly-typed code is a menace, but often a necessary one. Anything that makes it safer is a winner in my book.

> 	• Does this proposal fit well with the feel and direction of Swift?

Yes. It's particularly reminiscent of #selector, but it actually goes further by providing a feature people had to hack into Objective-C with horrible macros.

> 	• If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

That's...actually kind of an interesting question. But my thoughts on that matter are not on topic for this review, so for now I'll say no, I don't have any relevant experience.

(Well, I have seen various horrible macros which offer some semblance of typo safety for KVC. But these are best not spoken of.)

> 	• How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

I read the proposal and participated in the discussion.

-- 
Brent Royal-Gordon
Architechies



More information about the swift-evolution mailing list