Alfons
Alfons

Reputation: 1845

Swift closures, closure signatures, and closure equivalence

I'm kind of curious why this closure assignment works in Swift 4.1 (not tested yet under Swift 4.2, but both snippets don't work in Swift <= 4.0):

func intArrayFunc(_ policy: Int = 0,  completion: (([Int]?, Error?) -> Void)? = nil) {
    print("policy = '\(policy)'")
    completion?([policy + 2], nil)
}

typealias anyArrayClosure = (Int, (([Any]?, Error?) -> Void)?) -> Void

let a: anyArrayClosure = intArrayFunc(_:completion:)

a(1) { (results, error) in
    results?.forEach({ (result) in
        if let oneResult = result as? Int {
            print("\(oneResult) (Should be 3)")
        }
    })
}

However, this doesn't:

func t1(_ int: Int = 0, array: [Any]? = nil) {
    print("t1")
}

func t3(_ int: Int = 0, array: [Int]? = nil) {
    print("t3")
}

typealias function = (Int, [Any]?) -> Void

let t2: function = t1
let t4: function = t3

Or is it a just a bug in the 4.1 compiler?

Upvotes: 0

Views: 180

Answers (1)

Rakesha Shastri
Rakesha Shastri

Reputation: 11243

Observation 1

func t1(_ int: Int = 0, array: [Any]? = nil, completion: ((Int) -> ())) {
    print("t1")
}

func t3(_ int: Int = 0, array: [Any]? = nil, completion: ((Int) -> ())) {
    print("t3")
}

typealias function = (Int, [Int]?, ((Any) -> ())) -> Void

let t2: function = t1
let t4: function = t3

This works because t2 and t4 will take Int arguments which are compatible with the Any in t1 and t3, but if you do the opposite it won't because, Int cannot accept an Any value.


Observation 2

Now the closure is again receiving an argument. So if pass an Int argument to Any it is valid, but if you pass Any to an Int, it isn't.

So, this doesn't work.

func t1(_ int: Int = 0, array: [Any]? = nil, completion: ((Int) -> ())) {
    print("t1")
}

func t3(_ int: Int = 0, array: [Any]? = nil, completion: ((Any) -> ())) {
    print("t3")
}

typealias function = (Int, [Int]?, ((Int) -> ())) -> Void

let t2: function = t1
let t4: function = t3

So ultimately, it boils down to the simple fact that whatever you are passing to a variable should be compatible with it's type. You can pass and Int to Any but not vice-versa.

Upvotes: 1

Related Questions