Moreover, there aren't really any big differences between an unspecialized struct and an unspecialized function. Consider the following example:
struct foo<T> {
init(_: T) { }
}
func bar<T>(_: T) { }
foo<Set>([2])
bar([2])
The only notable difference is that with bar, you cannot tell the compiler that T is a Set and not an Array. To use a literal Set, you currently have to explicitly cast [2] to a Set or assign it to a variable whose type is specified and pass that into bar. Either way, this seems excessive and verbose.
The need for generic function specialization really becomes apparent though when using a closure whose body is type-checked separately for the expression itself and when a generic argument only takes up part of the type signature like in my tryFutureMap example above. Consider the more following example:
struct foo<T> {
init(_: @escaping (@escaping (T, Float, Double, String) -> Void) -> Void) { }
}
func bar<T>(_: @escaping (@escaping (T, Float, Double, String) -> Void) -> Void) { }
foo<Int> { baz in
baz(1, 2.0, 3.0, "")
baz(4, 5.0, 6.0, "")
}
bar { (baz: @escaping (Int, Float, Double, String) -> Void) in
baz(1, 2.0, 3.0, "")
baz(4, 5.0, 6.0, "")
}
Specializing foo with Int as its generic parameter gives the compiler the knowledge it needs to not require the type of baz be stated. With this in mind, it seems entirely unnecessary that the caller of bar should have to specify the entire type of baz, even though the compiler knows its type with exception of the single Int argument as T. When not specified, the compiler emits the error message "Generic parameter 'T' could not be inferred." It does not need all of baz, just T, though in Swift's current state you can't just provide the type of T. Allowing functions to explicitly specify their specialized generic parameters allows the line of bar's call-site to be reduced to bar<Int> { baz in, just like foo.
Providing functions with the ability to explicitly specialize their generic type parameters allows you to omit unnecessary information that the compiler already knows, thus removing redundancies and cleaning up the call-site.