Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

is it possible to create a generic closure in Swift?

func myfunc<T>(i:T) -> T {
    return i
}

is it possible to make this generic function a closure?

let myfunc = { <T>(i:T) -> T in
    return i
}

this doesn't work...

like image 879
Ken Zhang Avatar asked Aug 28 '14 09:08

Ken Zhang


People also ask

How do I create a generic in Swift?

Here, the generic function is created with type constraints. This means addition() can only work with data types that conform to Numeric protocol ( Int , Double , and so on). Note: If we try to pass other types, say String , we'll get an error: argument type 'String' does not conform to the expected type 'Numeric' .

How many types of closures are there in Swift?

As shown in the above table, there are three types of closures in Swift, namely global functions, nested functions, and closure expressions. They differ in several aspects, including their use scopes, their names, and whether they capture values, which will be discussed more in a later section.

Can a closure be assigned to a variable Swift?

Closures are self-contained blocks of functionality that can be passed around and used in your code. Said differently, a closure is a block of code that you can assign to a variable. You can then pass it around in your code, for instance to another function.


3 Answers

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.

like image 149
newacct Avatar answered Oct 02 '22 00:10

newacct


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)
        }
    }
like image 28
Konstantin Khamenok Avatar answered Oct 02 '22 00:10

Konstantin Khamenok


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) // -> Int
let y = myFunc("foo") // -> String

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

like image 31
Palle Avatar answered Oct 01 '22 23:10

Palle