[swift-evolution] Smart KeyPaths
Matthew Johnson
matthew at anandabits.com
Wed Mar 22 11:25:09 CDT 2017
> On Mar 22, 2017, at 11:00 AM, Vladimir.S <svabox at gmail.com> wrote:
>
> On 22.03.2017 18:47, Matthew Johnson wrote:
>>
>>> On Mar 22, 2017, at 10:36 AM, Vladimir.S via swift-evolution
>>> <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>>>
>>> On 22.03.2017 17:37, Ricardo Parada wrote:
>>>>
>>>>
>>>>> On Mar 22, 2017, at 9:30 AM, Vladimir.S <svabox at gmail.com
>>>>> <mailto:svabox at gmail.com>> wrote:
>>>>>
>>>>> let path = @Bag.things[0].name
>>>>>
>>>>> bag at path
>>>>> bag at .things[0].name
>>>>> bag at Bag.things <mailto:bag at Bag.things>[0].name
>>>>> bag.things[0]@.name
>>>>> bag.things[0]@Thing.name
>>>>
>>>> It sounds like the @ character is serving two different purposes which
>>>> confused me at first.
>>>>
>>>> If I understood correctly, you are using it to get the key path but also
>>>> to apply the key path to the bag struct and get the corresponding value.
>>>>
>>>
>>> Yes. And the initial proposal suggest the following syntax accordingly:
>>>
>>> let path = Bag.things[0].name
>>> bag[path]
>>> bag[.things[0].name]
>>> bag[Bag.things[0].name]
>>> bag.things[0][.name]
>>> bag.things[0][Thing.name]
>>
>> # makes a lot more sense than @ as a sigil. It follows from #selector and
>> #keyPath. These are the most similar language features right now where the
>> compiler produces special values. I think it’s also worth noticing that
>> values produced by #selector and #keyPath are /used/ in normal ways. There
>> is no magic syntax for their use, just a typed value. If we’re going to
>> make a change we should use # instead of `.` for accessing these special
>> values but we should stick with subscript for use.
>
> Could you clarify, what do you suggest? Something like this:
> let path = Bag#things[0]#name
I would only use one # at the start of the key path. Dots could be used afterwords like this: `Bag#things[0].name` I think it is important to use normal expression syntax after the key path is introduced.
> bag[#path]
No, you would just say `bag[path]`. `path` is a normal value and the subscript taking a path is a normal subscript.
> bag[#things[0]#name]
Here we have a type context expecting a key path with a root of the type of `bag`. There is no potential ambiguity involved in using the `.` here unless people extend the key path types with static members themselves. I think it’s fair to say do that at your own risk. So there is no need to use special synatx - dot shorthand would work just fine with no ambiguity problem. You could imagine the compiler synthesizing static members on key path types like this:
extension PartialKeyPath where Root == BagType {
static var things: KeyPath<Root, ThingsType> // or WriteableKeyPath or ReferenceWritableKeyPath
}
You just say: `bag[.things[0]#name]` using the existing dot shorthand for static members that return a value matching the type they are declared on.
On the other hand, it would be more consistent to introduce # shorthand here and not have the imaginary / synthesized static members on the key path types. I’m neutral, leaning towards using # shorthand for this.
> bag[Bag#things[0]#name]
As above, there is no need for a second `#`. Once the expression has produced a key path all subsequent chained accesses will also produce a key path.
bag[Bag#things[0].name]
> bag.things[0][#name]
As above, here we have a type context in the subscript that expects a key path. We could use the existing dot shorthand and compiler synthesized static properties on key path types or just introduce a # shorthand. The latter is probably better for consistency.
> bag.things[0][Thing#name]
Sure, if you don’t like the shorthand.
>
> ,and so
> let ref = Bag#foo()
Yep.
One interesting thing to note is that we could also get deep references to unbound methods. This would effectively combine key paths with unbound method references:
let doSomething = Bag#things[0].doSomething()
used like this:
doSomthing(bag)
Using # for key paths also allows us to build on it in the future for collection operators:
Bag#things[#sum].value // a key path that sums the value of all things in a bag
Reserving this potential is one important reason to only use # where you are introducing a special key path expression and not everywhere in the key path chain.
>
> ?
>
> In this case I feel like the following will be more clean syntax:
> let path = #Bag.things[0].name
> bag[#path]
> bag[#.things[0].name]
> bag[#Bag.things[0].name]
> bag.things[0][#.name]
> bag.things[0][#Thing.name]
> let ref = #Bag.foo()
This is kind of weird because Bag doesn’t have a static things property. I think it’s better to start put the # in the middle. That said, this would work as well.
>
> And why subscript is the only good candidate for use?
It is how Swift models parameterized value access. Building on that model makes a ton of sense. I can’t imagine a compelling argument for using key path values.
> Actually, for me personally, any solution will be good as soon as it contains some 'marker' which saying "hey, here key paths are used. be aware."
>
>>
>>> _______________________________________________
>>> swift-evolution mailing list
>>> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170322/6dc3bbb4/attachment.html>
More information about the swift-evolution
mailing list