Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How is it that U[] is castable to T[]?

It is clear that the T[] array type is not covariant as the elements of a T[] can be set by index.

And yet, a U[] can be cast to a T[] without any complaints from the compiler as long as U derives from T.

Man[] men = new[] { new Man("Aaron"), new Man("Billy"), new Man("Charlie") };
Person[] people = (Person[])men;

In the above code it appears that men and people do seem to hold a reference to the same Array object. The effect of setting men[0] = new Man("Aidan") can be seen at people[0]. Similarly attempting people[0] = new Woman("Debbie") results in an ArrayTypeMismatchException at runtime*.

Does this mean that the T[] type actually performs type checking on every set call? It seems that this must be necessary if it is allowed to cast arrays in this manner.

I guess my question is just: How is this possible? It's clear to me that U[] does not derive from T[]. It's also unclear to me whether I could ever define my own type that would work in this way: actually be invariant but act covariant.


*Though array variance is apparently permitted by the CLR, any language could disallow casting between array types. However, it appears that this behavior is identical in VB.NET:

Dim men = New Man() { New Man("Aaron"), New Man("Billy"), New Man("Charlie") }
Dim people = CType(men, Person())
like image 585
Dan Tao Avatar asked Aug 31 '10 17:08

Dan Tao


3 Answers

This is a special behavior of arrays and cannot be replicated in any other type.

It is generally regarded as a mistake.

like image 140
SLaks Avatar answered Nov 15 '22 07:11

SLaks


This works just because it is a special feature that is part of the CLR. Arrays are automatically covariant even though technically they aren't. Compilers just have to know this and generate the proper type checks.

Although some consider this feature a mistake, it was very important to have prior to typesafe collections and generic interface covariance. You would not even be able to write a function to sort an array without it.

like image 32
Gabe Avatar answered Nov 15 '22 05:11

Gabe


Eric explained it very clearly here: http://blogs.msdn.com/b/ericlippert/archive/2007/10/17/covariance-and-contravariance-in-c-part-two-array-covariance.aspx.

Short resume: if D inherits B then D[] is covariant to B[]. Assume D2 also inherits from B, then

B[] b = new D[10]; 
b[0] = new D1();

throws exception. Yes, this is not good but it is so.

like image 28
Andrey Avatar answered Nov 15 '22 07:11

Andrey