When writing an algorithm that uses a predicate function, it is often necessary to pass the negated version of that predicate to another function. This occurs both in the standard library and user code.
The way to achieve this today is, eg:
let i = try myCollection.firstIndex{ try !predicate($0) }
That works, but for simplicity and clarity I’d rather write:
let i = try myCollection.firstIndex(where: !predicate)
So I made a helper function to negate a boolean predicate function:
prefix func ! <T> (_ f: @escaping (T) throws -> Bool) -> (T) throws -> Bool {
return { try !f($0) }
}
This works, but the problem is that it requires f
to be marked as @escaping
, which means the predicate in the calling code must itself be @escaping
, and this propagates virally.
I’m aware of the withoutActuallyEscaping
function, but I’m hesitant to use it here since f
really does escape the negation function.
Furthermore, even if I deal with the escaping-ness, when I try to use this in practice I run into issues with rethrows
:
extension Collection {
func firstIndexWhereNot(_ predicate: @escaping (Element) throws -> Bool) rethrows -> Index? {
// error: a function declared 'rethrows' may only throw if its parameter does
return try firstIndex(where: !predicate)
}
}
Of course, we reading the code understand that !predicate
can only rethrow errors from predicate
, but the compiler doesn’t know that.
So, I’m wondering if there’s a proper way to do this.
I recognize that the actual syntactic change at the point of use is quite small. But for me personally, code written with !predicate
is much easier to read, and its meaning is clear at a glance.
Achieving this seemed so simple on the surface: I have a closure that returns a Bool
, and I want a new closure that returns its negation.
But when I try to actually make it work, I keep running into roadblocks.