Claude
Claude

Reputation: 43

How to fix : "passing non-escaping parameter to function expecting @escaping closure"

I'm experimenting usage of closurse for First Order Predicate calculus, and I intend to define the following function :

func ASSUM<U, V>(p: @escaping Pred<U>) -> (Pred<U>) -> Pred<(U, V)> {
    return { q in AND1(p: p, q: q) }
}

that takes as parameter a predicate p: Pred<U>, where Pred<U> is a typealias for (T) -> Bool:

typealias Pred<T> = (T) -> Bool

The return of ASSUM is a Predicate transformer closure of type (Pred<U>)->Pred<(U,V)>.

However the compiler return the following error :

Passing non-escaping parameter 'q' to function expecting an @escaping closure

I understand that the function AND1 as defined requests an escaping parameter :

func AND1<U, V>(p: @escaping Pred<U>, q: @escaping Pred<V>) -> Pred<(U, V)> {
    return { (x, y) in (p(x) && q(y)) }
}

but I did not succeed in explicitly making q in { q in AND1(p: p, q: q) } escaping.

How can I fix this?

Upvotes: 2

Views: 1488

Answers (1)

dfrib
dfrib

Reputation: 73176

You must explictly add the @escaping attribute to the argument of the return type closure of ASSUM:

typealias Pred<T> = (T)->Bool

func AND1<U, V>(p: @escaping Pred<U> , q: @escaping Pred<V>) -> Pred<(U, V)> {
    return { (x,y) in (p(x) && q(y)) }
}

func ASSUM<U, V>(p: @escaping Pred<U>) -> (@escaping Pred<V>) -> Pred<(U, V)> { 
                                                       /* ^ note: I believe you 
                                                            want V here, not U  */
    return { AND1(p: p, q: $0) }
}

In the returned closure, q (anonymous $0 argument) is correctly inferred as @escaping (and needn't be explicitly marked as such, as pointed out by @Hamish, thanks!).

Note also that the generic type V in ASSUM must be inferred by explicit type annotation (or conversion) by the caller, as it is not included in any of the arguments to ASSUM.

/* example usage */
let foo = { $0 < 2 }
let bar = { $0 != "bar" }

let fooAnd: (@escaping Pred<String>) -> Pred<(Int, String)> = ASSUM(p: foo)
let fooAndBar = fooAnd(bar)

print(fooAndBar((1, "foo"))) // true
print(fooAndBar((1, "bar"))) // false
print(fooAndBar((2, "foo"))) // false

Finally, ALLCAPITAL function names is not in line with the Swift naming convention: you should prefer camelCase naming instead (see e.g. the Swift API guidelines for additional details).

Upvotes: 1

Related Questions