I just noticed that Array and Value are covariant, but general generic placeholders are invariant:
class Base {}
class Derived: Base {}
struct Foo<Value> {}
// Ok
let array: Array<Base> = Array<Derived>()
// Fail
let foo: Foo<Base> = Foo<Derived>()
You can even down cast [Base] to [Derived] using as! with appropriate values.
Is this a special behaviour, or is there a way to annotate it?
4 Likes
The type checker hardcodes conversions from Array<T> to Array<U> if there is a conversion from T to U. Similar rules exist for Optional and Dictionary. There's no mechanism for doing this with your own types.
12 Likes
Why does let foo: Foo<Base> = Foo<Derived>() fail?
I was totally expecting it to compile.
Karl
(👑🦆)
4
Because they are treated as entirely unrelated types. As Slava explained, the covariance we have is special-cased for a few hand-picked standard library types only.
1 Like
I guess then my question is, why are they treated as entirely unrelated types? 
Karl
(👑🦆)
6
Because for a generic type Foo<T>, the compiler doesn’t know how the type Foo uses T.
Are you reading Ts from your Foo? If so, you’ll be reading Base from something that actually contains a Derived. That’s fine.
But what if you’re storing (i.e. setting) Ts in to your Foo? Then you’ll be able to set a value of type Base in to something that expects a Derived. That’s not fine.
(To be clear: when you write let foo: Foo<Base> = Foo<Derived>(), the dynamic type of foo is Foo<Derived>. That’s what it “really” is, and what determines is layout, etc. The static type is Foo<Base>, which is the interface you want to use to interact with it. You’re using it as if it was a Foo<Base>)
6 Likes
Because it is not sound to treat them as interchangeable types, or to treat one as a subtype of another, in the general case. For example, suppose you have this very simple generic container:
class Foo<T> {
var t: T
}
Now this function takes a Foo<Base> and stores a new instance of Base in there:
func takesFooBase(_ foo: Foo<Base>) {
foo.t = Base()
}
And this function takes a Foo<Derived> and prints out foo.t, which must be an instance of Derived since T is Derived:
func takesFooDerived(_ foo: Foo<Derived>) {
print(foo.t)
}
Now imagine you could do this:
let fooDerived = Foo<Derived>()
let fooBase: Foo<Base> = fooDerived
takesFooBase(fooBase)
takesFooDerived(fooDerived)
What would happen?
7 Likes
Somebody asked about this on Stack Overflow and then I came here and saw this. Is there a more general solution for conversion than what I thought of there, that people use? I thought of that while I was asleep and it doesn't seem that usable.
Great example, thank you 
I guess I was expecting the compiler to somehow change the dynamic type of fooDerived to Foo<Base> upon assignment to fooBase. But that would break fooDerived: Foo<Derived>.