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.
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.
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>)
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:
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.
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>.