Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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
like image 383
bteapot Avatar asked Sep 12 '25 01:09

bteapot


1 Answers

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.

like image 173
Hamish Avatar answered Sep 14 '25 22:09

Hamish