Key Path Expressions as Functions for equivalent functions

In the proposal, now in Swift 5.2, we know keypath expressions are converted to functions. But these functions don't override equivalent functions. However, I can normally pass a non-optional value where an optional value is expected.

Should Swift allow these kind of function overrides like normal functions?

struct S {
    let val: String
}
class C {
    var block: ((S) -> String?)?
}

let c = C()
c.block = { (s: S) -> String in
    return s.val
}
// Compiles perfectly fine
c.block = { (s: S) -> String? in
    return s.val
}

let f: (S) -> String = \S.val
let f2: (S) -> String? = \S.val // Error: Key path value type 'String' cannot be converted to contextual type 'String?'

Where I ran into this was trying to use keypaths in allSatisfy which expects a function that throws.

class C {
    var block: ((S) throws -> String)?
}
let c = C()
c.block = { (s: S) throws -> String in
    return s.val
}
c.block = { (s: S) -> String in
    return s.val
}
[true, true].allSatisfy({ $0 }) // Compiles fine
[true, true].allSatisfy(\.self) // Error: Cannot convert value of type 'WritableKeyPath<_, _>' to expected argument type '(Bool) throws -> Bool'

Edit:
I just realized the .allSatisfy(\.self) example doesn't work, but if I refer to a property it does work just fine. I think it's an error with WritableKeyPath.

2 Likes
Terms of Service

Privacy Policy

Cookie Policy