swiftswift4keypaths

Reference to self with Swift 4's KeyPath


Is there any way to reference self with Swift 4's new KeyPaths?

Something like this works fine, we can address a property of an object:

func report(array: [Any], keyPath: AnyKeyPath) {
    print(array.map({ $0[keyPath: keyPath] }))
}

struct Wrapper {
    let name: String
}

let wrappers = [Wrapper(name: "one"), Wrapper(name: "two")]
report(array: wrappers, keyPath: \Wrapper.name)

But addressing an object itself seems impossible to me:

let strings = ["string-one", "string-two"]
report(array: strings, keyPath: \String.self) // would not compile

I suppose there should be some obvious way for this?

EDIT:

Or simply:

let s = "text-value"
print(s[keyPath: \String.description]) // works fine
print(s[keyPath: \String.self]) // does not compile

Solution

  • Unfortunately, this isn't something Swift keypaths currently support. However, I do think this is something they should support (with the exact syntax you're attempting to use, e.g \String.self). All expressions have an implicit .self member that just evaluates to the expression, so it seems like a perfectly natural extension to allow .self in keypaths (Edit: This is now something that's being pitched).

    Until supported (if at all), you can hack it with a protocol extension that adds a computed property that just forwards to self:

    protocol KeyPathSelfProtocol {}
    extension KeyPathSelfProtocol {
      var keyPathSelf: Self {
        get { return self }
        set { self = newValue }
      }
    }
    
    extension String : KeyPathSelfProtocol {}
    
    let s = "text-value"
    print(s[keyPath: \String.description])
    print(s[keyPath: \String.keyPathSelf])
    

    You just need to conform types that you want to use "self keypaths" with to KeyPathSelfProtocol.