The most common use for existentials is to be able to store heterogenous types in a collection that requires a single homogenous element type. It's also common to want to write extension Collection where Element: SomeProtocol
in order to do generic processing on any collection where an element conforms to a protocol. Lack of existential conformance confounds this.
For example:
// our docs admonish you not to use CustomStringConvertible
// this way, but let's ignore that for now...
extension Collection where Element: CustomStringConvertible {
func prettyPrint() {
let strings = self.lazy.map { $0.description }
print( "[\(strings.joined(separator: ", "))]" )
}
}
let someInts: [Int] = [1,2,3]
someInts.prettyPrint()
// [1, 2, 3]
let somePrintableThings: [CustomStringConvertible] = [1,"two",3]
somePrintableThings.prettyPrint()
// error: value of protocol type 'CustomStringConvertible' cannot conform
// to 'CustomStringConvertible'; only struct/enum/class types can conform
// to protocols
// And yet you can just take the body of prettyPrint and use it...
let strings = somePrintableThings.lazy.map { $0.description }
print( "[\(strings.joined(separator: ", "))]" )
// [1, two, 3]
This to me makes the clear case that this is a hole in the language that should be fixed.
I do worry that existentials are already significantly overused, and I wish people would treat them as a last rather than first resort more often. But we shouldn't not fix their legitimate use just because of that, even if I fear that will lead to even more misuse.