+1
I just encountered a situation where this would have been helpful:
struct ManagedArrayBuffer<Header, Element> {
init(minimumCapacity: Int, initialHeader: Header)
}
struct MyStorage<Header> {
var codeUnits: ManagedArrayBuffer<Header, UInt8>
init(...) {
// Element == UInt8 inferred here
self.codeUnits = ManagedArrayBuffer(minimumCapacity: c, initialHeader: header)
}
}
Refactoring this code, I was exploring making the MAB initializer failable and propagating that through MyStorage's initializer. This meant it needed to be stored in a local variable, which lost the inference of the Element type, and meant that I had to write out the entire generic signature:
struct MyStorage<Header> {
var codeUnits: ManagedArrayBuffer<Header, UInt8>
init?(...) {
// Error: Cannot infer type of 'Element'.
guard let storage = ManagedArrayBuffer(minimumCapacity: c, initialHeader: header) else {
return nil
}
self.codeUnits = storage
}
}
I actually had to split the new version up across multiple lines, it was so long:
guard let storage = ManagedArrayBuffer<Header, UInt8>(
minimumCapacity: c,
initialHeader: header
) else {
return nil
}
This feature would have allowed me to write:
guard let storage = ManagedArrayBuffer<_, UInt8>(minimumCapacity: c, initialHeader: header) else {
return nil
}
It's kind of annoying to have to go through all of these steps for quite a simple thing. Swift has type inference because it's convenient and makes code easier to read (which comes with lots of positive side-effects), but right now it's binary - either it can infer everything, or it infers nothing. So I like the idea of being able to fill in the gaps and enabling inference to work in more situations.
The benefits also scale nicely if you have longer, more descriptive type names (which Swift encourages) that can now be omitted, or if you have more generic parameters.