[swift-evolution] Smart KeyPaths

Matthew Johnson matthew at anandabits.com
Wed Mar 22 15:49:28 CDT 2017

> On Mar 22, 2017, at 3:30 PM, Brent Royal-Gordon <brent at architechies.com> wrote:
>> On Mar 22, 2017, at 11:27 AM, Matthew Johnson via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>> One option would be to include `get` and `set` methods on the key path types.  That would allow us to write the subscripts in the standard library (if it is allowed to extend Any) and keep all of the magic in the key path types themselves.  I think I would like that approach.
> This is not a good option. Although we Swift users may write `get` and `set` accessors, the real primitives in Swift are `get` and `materializeForSet`, which is basically "return a pointer that can be modified until another call is made which finalizes the set". `materializeForSet`'s call sequence is too low-level to be written manually; without adding other features to the language, we're basically left with either calling a method that calls a closure with an `inout` parameter, or using a subscript.

This is what I had in mind (synthesized by the compiler):

extension WritableKeyPath {
    func get(from root: Root) -> Value { … }
    func set(to value: Value, on root: inout Root) { … }

And something like this in the standard library:

extension Any {
    subscript<Root: Self, Value>(path: WritableKeyPath<Root, Value>) -> Value { 
        get {
            return path.get(from: self)
        set {
            path.set(to: value, on: &self)

Is there a reason this wouldn’t work?  I’m only presenting it for the sake of discussion.  I don’t have a strong opinion about it one way or the other.  The nice thing about it is that it keeps the magic in the key path types.

> The ownership manifesto includes a generator feature which could, some day, make it possible to write a method wrapping `materializeForSet`. But subscripts allow us to do this today, and it's *perfectly* natural to think of key paths as being a subscript; subscripts are for accessing values inside an instance, and a key path addresses a value inside an instance, too.

I definitely think the subscript syntax should be supported.  I’m only suggesting an option that might allow us to keep all of the compiler magic in the key path types.

> I guess I just don't understand why people seem so eager to change this syntax. The biggest complaint seems to be that it's too lightweight and natural; they're worried they might not realize they're using this big, scary new feature. But this feature simply *isn't* big and scary! It's new right now, but in a few years it's going to feel very natural.

I’m not eager.  I’m just discussing options that are acceptable to me because a lot of people seem to want something different.  I’m happy with the syntax included in the proposal as well.

> I can't find it now, but I once read someone state that this is part of what happened to C++: Every time someone proposed a new feature, people were worried that they would use it by accident, so they insisted that it have an unmistakable, obvious syntax so you would know you were using it. The result is that now, almost every syntax in C++ is shouting at you that you're using feature X, Y, or Z, and you can't hear your own code over the din.

A good cautionary tale.  I’m pretty neutral between the syntax in the proposal and the # sigil idea.  Regardless of which we go with, I think there is some value in exploring how we might keep the compiler magic in the key path types.

> Key paths are about as nonthreatening as a syntax can be. They overload some things, but the type checker will catch most overloading mistakes. Other than that, there's just no justification for the level of anxiety people seem to have. They don't break type safety, they don't involve unusual or non-obvious control flow, they don't trap, and they can be explained in a couple of sentences. If ever there was a candidate for a lightweight syntax, this is it. 

Agree.  They can also be conceptualized as compiler synthesized static properties if we move forward with the syntax in the current proposal.  There is nothing wrong with this model aside from a minimal risk of ambiguity (which I don’t think is worth worrying about).

> As the protest sign says: "I want YOU to stop being afraid". I have yet to be convinced that this feature is too dangerous or mistake-prone to allow the simple, natural syntax the authors propose. If I'm wrong, then by all means show me I'm wrong, but I just don't see it.

I agree that the fear seems to be overblown.  That said, key paths are synthesizing special values in a way that has some similarity to #selector.  It has also been pointed out that # could resolve some issues we have right now with unbound methods.   If it makes people feel better to use # to access unbound members and it solves a problem, maybe it’s worth considering.

Overall, I’m pretty neutral on this topic.  I’m mostly trying to guide people away from discussing syntax options that I think are bad ideas.  I guess that’s what you’re trying to do also.  :)

> -- 
> Brent Royal-Gordon
> Architechies

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170322/2d1828bf/attachment.html>

More information about the swift-evolution mailing list