Why KeyPath?

Thanks. I misunderstood Rob's example code. I realized it and delete my question before I saw your reply.

As nominal types, key paths can be extended with protocol conformances, methods, and properties. Functions cannot be so extended. I haven't had an occasion to use that ability though (beyond the built-in conformances).

2 Likes

A fun thing I contemplated back in the day is "what if key paths could get conditional conformances based on attributes* of the properties along the path?". I think this might boil down to accidentally making a generalized effects system again, but it was a cute idea.

*for whatever definition of attributes.

2 Likes

That should be possible now that we do support protocol compositions with base classes. WritableKeyPath is already burned in as a subclass, it would definitely be more composable to introduce new capabilities like KeyPath<T, U> & Sendable & Codable by protocol composition rather than by extending the class hierarchy. We also have more generalized existentials than we used to, so at some point it might be nice to supersede the KeyPath class itself with a protocol now that we can express types like any KeyPathProtocol<T, U>.

12 Likes

So, trying to boil this down to an elevator pitch on KeyPaths. What I have so far is:

KeyPaths allow you to hand over a reference to a member of a type, as opposed to the value of that member at the present time, which can be useful for when something need to know not only what value to work with, but also what member of that value is important. For instance, if you have a structure with several members, a KeyPath can be used to say which member ought to be used to sort with.

So, given:

struct Worker {
  var name: String
  var title: String
  var division: String
}

func consider(worker: F, workerData: KeyPath<F, String>) {
    print(worker[keyPath: workerData])
}

let x = F(name: "Jack", title: "Tradesman", division: "Mechs")

consider(follower: x, followerItem: \.division) // prints "Mechs"

Okay, that much makes sense to me.

1 Like

does KeyPath still use reference counting?

despite knowing exactly what AnyObject-constrained existentials are, for some reason my brain still thinks of the any keyword as “slower” than a polymorphic class instance. old prejudices die hard…

Another benefit of a protocol is that you could define types and functions generic over the protocol in order to store the information for a particular keypath inline without wrapping.

I use keypaths with map every single day, much clearer than using closures.

1 Like

While "clearer" doesn't represent how I feel about \., $ is the most nonsense-looking, American-capitalism-touting, rump-ugliest thing in the language. It was bad enough with $0—at least that could be avoided by supplying a name. Property wrappers + SwiftUI made it impossible.
:money_mouth_face:

3 Likes

Yeah, having suffered through the hardworking weirdness that is Perl for years as a sys-admin, I’m not a big fan of the use of sigils. This applies to Optionals as well. I’m used to it, but that’s as far as I’ll go.