Covariant generic types make for an unsound type system. I believe the reason 
why Array and Optional are covariant in their generic parameter is that the way 
their implementation interacts with their internal storage assures that new 
storage is created if types mismatch: this means that to make covariance work 
for generic types you have to be extra careful when using references, because 
it doesn't really make sense from a mathematical standpoint (from my 
understanding of the matter).

What could probably be useful in your case is the concept of "generalized 
existential", which is considered in the generics manifesto (
 ) and I believe is something that will eventually be added to Swift in the 
future because many use cases have come up in the mailing list over time: for 
example smart KeyPaths were implemented with classes instead of structs and 
protocols because of the lack of generalized existentials in the language.


> Il giorno 08 ago 2017, alle ore 00:00, Logan Shire via swift-evolution 
> <> ha scritto:
> One of my longstanding frustrations with generic types and protocols has been 
> how hard it is to work with them when their type is unspecified.
> Often I find myself wishing that I could write a function that takes a 
> generic type or protocol as a parameter, but doesn’t care what its generic 
> type is.
> For example, if I have a type:
> struct Foo<T> {
>     let name: String
>     let value: T
> }
> or:
> protocol Foo {
>     associatedtype T
>     var name: String { get }
>     var value: T { get }
> }
> And I want to write a function that only cares about, I’d like to be 
> able to:
> func sayHi(to foo: Foo) {
>     print("hi \(")
> }
> But instead I get the error, “Reference to generic type Foo requires 
> arguments in <…>”
> Also, when you want to have a polymorphic array of generic types, you can’t:
> let foos: [Foo] = [Foo(name: "Int", value: 2), Foo(name: "Double", value: 
> 2.0)]
> And if you remove the explicit type coercion, you just get [Any]
> let foos = [Foo(name: "Int", value: 2), Foo(name: "Double", value: 2.0)]
> I wish that could be inferred to be [Foo]. I’d like to propose being able to 
> use the non-generic interface of a type normally. 
> I.e. if you have a type Foo<T>, it is implicitly of type Foo as well. The 
> type Foo could be used like any other type.
> It could be a parameter in a function, a variable, or even the generic type 
> of another type (like a Dictionary<String, Foo>)
> The only restriction is that if you want to call or access, directly or 
> indirectly, a function or member that requires the generic type,
> the generic type would have to be known at that point.
> Foo<T> should be able to be implicitly casted to Foo wherever you want, and 
> Foo could be cast to Foo<T> conditionally.
> Initializers would still obviously have to know the generic type, but given 
> the above example, you should be able to:
> let names = { $ }
> However, you could not do the following:
> let foos = [Foo]()
> Because the initializer would need to know the generic type in order to 
> allocate the memory.
> Let me know what you think!
> —
> Logan Shire
> iOS @ Lyft
> _______________________________________________
> swift-evolution mailing list

swift-evolution mailing list

Reply via email to