Sure. By context here I mean the generic context, which is the information around your use or declaration that the compiler can use to infer the type. Say you had an asynchronous decoding method. Like other decoding methods you'd declare it generically:
func decode<T: Decodable>decode(_ completion: (T) -> Void)
Due to the use of the closure, Swift's type inference can't determine the type of T just from the context:
decode { decoded in // Error: Generic parameter 'T' could not be inferred.
let string: String = decoded
}
Instead, you need to provide the type directly in the closure definition:
decode { (decoded: String) in
let string = decoded
}
As you can see, this is fairly awkward, especially if the type is complex or uses other generic types. So we can offer a different API to make it a bit easier:
func decode<T: Decodable>(type: T.Type, _ completion: (T) -> Void)
This allows us to pass the type directly, separately from the completion handler.
decode(type: String.self) { decoded in
let string = decoded
}
While that works fine, it does make the API more verbose, especially when the type could be otherwise inferred. It also limits the usage of the method to contexts where you can pass the type directly. So this becomes impossible:
func wrapped(_ completion: (String) -> Void) {
decode(type: // How do I get the type?, ...)
}
The solution is to default the parameter to contextual generic type so that it can be used in either scenario:
func decode<T: Decodable>(type: T.Type = T.self, _ completion: (T) -> Void)
This allows you to successfully use it in both of the previous examples:
decode(type: String.self) { decoded in
let string = decoded
}
and
func wrapped(_ completion: (String) -> Void) {
decode(completion)
}
In the second case, the complier knows the type you want decoded is String and can successfully pass it that information through to decode due to the use of the defaulted argument.