This was previously discussed here, but the discussion seems to have dropped off:
In the time since that was posted, while investigating how difficult it would be to support, I found that the existing constraints fully support this feature, and it's purely restricted syntactically.
I would like to propose we lift this restriction, which would allow using type inference in more places, e.g. specializing function references.
For example, ideally I would like to be able to write a function like this, which uses contextual information to determine what the decoding output.
final class MyDecoder: Decoder {
func decode<T>(from data: Data) throws -> T
}
In order to use it, I either have to pass it to a context which I know the type is derivable, or provide a type annotation. In both cases, I have to somewhat play constraint solver on behalf of the compiler, lining up the types such that the constraint system is satisfied:
let value: MyType = try decoder.decode(from: data)
// or pass it to a function:
func processValue(_ value: MyType) { ... }
processValue(try decoder.decode(from: data))
or as a coercion
let value = decoder.decode(from: data) as MyType
But what I really want is to be able to provide the type arguments the same way I provide the function arguments, using the same syntax the type parameters are declared with:
let value = decoder.decode<MyType>(from: data)
This is already supported for type instantiation when resolving constructor declarations:
let value = Array<MyType>()
And you can form partially applied functions referencing these instantiated constructors:
struct GenericValue<T> { var value: T }
let createGenericValue = GenericValue<Int>.init
The canonical workaround that has become accepted in Swift is to provide the generic parameter as a metatype argument:
func decode<T>(_ type: T.Type, from: Data) throws -> T
But that requires providing MyType.self
, which is not something someone new to Swift would know to do. Many languages support this kind of explicit specialization for functions at the call site: C++, Java, Rust, C#, to name a few.
I think this restriction should be lifted, and I also think this should be preferred over the metatype parameter versions of generic functions like this. There's still value in taking meta types, like withTaskGroup
's returning:
argument label. That said, I think there's an argument to be made for labeled generic parameters as well.
I have an experimental PR up now to lift the restriction and update the tests. It generally does what you'd expect.
Thoughts? I would also appreciate more information if I'm missing something about the necessity of the restriction.