is it possible to create a generic closure in Swift? is it possible to create a generic closure in Swift? ios ios

is it possible to create a generic closure in Swift?


No, because variables and expressions can't be generic. There are only generic functions and generic types.


To clarify: In some languages you can have types with a universal quantifier, like forall a. a -> a. But in Swift, types cannot have a universal quantifier. So expressions and values cannot be themselves generic. Function declarations and type declarations can be generic, but when you use such a generic function or an instance of such a generic type, some type (which could be a real type or a type variable) is chosen as the type argument, and thereafter the value you get is no longer itself generic.


Probably you need something like this.

Type declaration:

typealias ResultClosure<T> = (ResultCode, String?, T?) -> Void

Function declaration:

func loginUser(userName: String, password: String, resultHandler: ResultClosure<TokenModel>?)

Usage:

    NetConnector.shared.loginUser(userName: userName ?? "", password: password ?? "") { (code, message, data) in        self.display?.unlockScreen()        if code == .success {            if let activeToken = data {                AppData.shared.userToken = activeToken            }            self.display?.showHome()        } else {            self.display?.showError(errorMessage: message)        }    }


As mentioned, variables in Swift cannot be generic, so creating a closure, whose generic types are specified by the caller is not possible. However, there are workarounds:

With SE-253, it is possible to make arbitrary (nominal) types callable. So instead of declaring a generic closure, we can declare a (non-generic) struct that has a generic callAsFunction method:

struct MyFunc {    func callAsFunction<T>(_ i: T) -> T {        return i    }}

Now, we can declare a non-generic variable that we can call with a generic value:

let myFunc = MyFunc()let x = myFunc(42) // -> Intlet y = myFunc("foo") // -> String

Note that this workaround doesn't apply to all situations, but it can be helpful in some.