clmntcrl
clmntcrl

Reputation: 273

Passing generic type over functions in Swift

In order to avoid code repetition I'm trying to find a way to infer argument type Tor () -> T from a variable of type U.

I don't know if I'm clear enough so this is what I wan't to do:

func f<T>(closure: () -> T) -> String {
    return "closure: () -> \(T.self)"
}
func f<T>(value: T) -> String {
    return "value: \(T.self)"
}

f("test1") // -> "value: Swift.String"
f({ return "test2" }) // -> "closure: () -> Swift.String"

func foo<U>(bar: U) -> (String, String) {
    return ("\(U.self)", f(bar))
}

foo("test3") // (.0 "Swift.String", .1 "value: Swift.String")
foo({ return "test4" }) // (.0 "() -> Swift.String", .1 "value: () -> Swift.String")

I expected foo({ return "test4" }) to call f<T>(closure: () -> T) function instead of f<T>(value: T). Why Swift can't infer that bar: U match with () -> T pattern ?

Upvotes: 2

Views: 535

Answers (1)

Chris Conover
Chris Conover

Reputation: 9039

TL;DR: Type data is lost with foo() / U.

I suspect that you are coming from a C++ background.

This would work in C++ as C++ infers the type based on the call site. Swift is different though, in that the generic parameter is the only source of type data. In your case, you are providing no information about the type U, so the compiler does not know how it could convert it to the closure type. Your value override of f() works because you are not placing any conditions on T, whereas in your closure type override, you are specifying a specific form (a closure). Since all type data is lost by your call through foo that takes generic (think blank) type U, the compiler does not have enough information, and cannot deduce a conversion from (blank) to a closure.

This is the topic of "type reification", and there is a lengthy discussion on this on devforums.apple.com.

Upvotes: 2

Related Questions