I think youβre conflating KeyPaths to method results with unapplied function references.
We can already make KeyPaths to subscript results, and this comes with some constraints: for example, the KP capture all the arguments and the arguments must be Codable. Only then can you create a KeyPath which refers to the result of calling that subscript with those parameters.
It would be nice to have some kind of KeyPath-like object for referring to unapplied method references, but that would almost certainly require variadic generics.
Thanks Rafael, that's a good point that I forgot to clarify.
class MyClass {
func myMethod(x: Int) -> String { ... }
static var myStaticProperty: (MyClass) -> (Int) -> String = { ... }
}
let a = MyClass.myMethod
let b = MyClass.myStaticProperty
let c = { (_: MyClass) in { (x: Int) -> String in ... } }
Each of these variables have the same type (a, b, and c), however each has drastically different implications on API usage, capture, type safety, optimisation, etc.
I'd like to have a type I can use to distinguish the MyClass.myMethod case, so it informs how an API should be used, and so it constrains what might be captured in the calling scope.
If you changed the type for the MyClass.myMethod syntax you suggested then you can't do this (without modifying map as well):
[1, 2, 3].map(Int.negate)
The key path syntax is currently incompatible with methods, and I think it is an appropriate place to put what I am suggesting.
From a type safety perspective what you're proposing with "unapplied function references" is equivalent of using (MyType) -> Int instead of KeyPath<MyType,Int>.
I want the equivalent type safety of KeyPath but for unapplied function references (perhaps I should have said this).
I don't believe this would require variadic generics, the implementation could benefit from it, but the public interface wouldn't require it.
We do have unbound methods currently (the feature @rguerreiro mentioned), but I believe during the keypath proposal review we agreed that this feature should probably be replaced by something more keypath-like.
I think the simplest solution is to extend keypaths to support instance methods as well as properties. Trying to split Arguments and Result into separate generic parameters leaves lots of holes in our support: not only throws, but also inout and @escaping and so on. There's also no particular reason we wouldn't want to form a "method path" to a method on a property of the type, so that existing feature is not out of place.
This won't support mutating methods, but keypaths don't currently support properties with mutating getters either. I could imagine a future version of Swift adding new keypath types to support both.
I could also imagine future versions of Swift allowing methods with parameters to be specified in the keypath chain, like \Array<Person>.first(where: predicate).name. That's a different feature from this one, though.
I think it'd be really useful (if it's not already possible) to pass arguments to an unapplied function reference which would provide a native builder-like pattern.
let builder = \Array<Person>.init(firstName: "John", lastName: "Doe")
...
let person = builder()