What you're doing above isn't keypath notation; it's just passing an instance-bound function to filter
. Is a trailing closure that much worse?
let fives = [1, 2, 3, 4, 5, 6, 7, 8, 9].filter { !digitsExceptForFive.contains($0) }
If your goal is succinct, functional programming, then adding special cases for individual APIs won't really get you there. Higher-order functions would be better, which could be applied to anything, not just contains
. Something like:
func not<T>(_ predicate: @escaping (T) -> Bool) -> (T) -> Bool {
{ !predicate($0) }
}
let fives = [1, 2, 3, 4, 5, 6, 7, 8, 9].filter(not(digitsExceptForFive.contains))
You can even make it an operator:
prefix func ! <T>(_ predicate: @escaping (T) -> Bool) -> (T) -> Bool {
{ !predicate($0) }
}
let fives = [1, 2, 3, 4, 5, 6, 7, 8, 9].filter(!digitsExceptForFive.contains)
Both of those work with keypaths, too, thanks to the implicit function conversion.
Combinators like these have their purpose, but I imagine some more exploration would be necessary before deciding the best form they should take if someone wanted to aim them at the standard library. There are still some missing pieces in the language that would make them much more complete, like variadic generics.