I think you're misunderstanding what covariant and contravariant positions are. It doesn't imply that you're able to cast between certain types, it just establishes the inheritance relationship between parameterized types.
You're only able to mark type parameters as in covariant or contravariant positions. When you say Container[+A]
, you're saying that you can treat all instances of Container[A]
as subtypes of Container[B]
if A
is a subtype of B
. This makes sense for immutable container classes: You can think of a List[Person]
to be a parent of List[Employee]
. Note this says nothing about casting rules -- those go unchanged.
Contravariant is similar, but the opposite. If you have Writer[-A]
, it says Writer[A]
is a subtype of Writer[B]
if B
is a subtype of A
. You can see how this makes intuitive sense too: If you have a Writer[Person]
as something that can write a Person into some destination and you have Writer[Employee]
as a writer that can only write Employees, it makes sense for Writer[Employee]
to be a parent of Writer[Person]
since writing a Person
is a sub-task of writing a full Employee
, even though it is the opposite for the types themselves.