Turtles are Reptiles, right?

While writing an article about co- and contravariance in .NET I stumbled over some funny C# behaviors.

Given a simple domain model of animals (Reptile is base of Snake and Turtle), will this actually work?

And if not, what will happen? Will it even compile?

Reptile[] reptiles = new[]
    new Snake("Leo"), 
    new Snake("Lucy")

reptiles[0] = new Turtle("Platschi");

Quite obvious, still odd. 🙂

GREAT! Thanks for the answers!

I think @thinkbeforecoding had the best answer. Justin Chase, Björn Rochel and Stefan Lieser also got it right.

Here is what happens:

  1. It compiles!
  2. The type inference will infer a Snake[] from new[] because all elements are Snake.
  3. The Snake array will then be implicitly casted to the Reptile array reptiles because C# supports covariance for Array element types.
  4. Line 7 also compiles fine. But the covariance support is unsafe, hence read-only. The Snake-Array behind the scenes can’t handle Turtles.
  5. A ArrayTypeMismatchException is thrown at runtime.

In C# 4.0 there will not be safe variance for Arrays either. There can never be safe co- and contra-variance for read-write-interfaces or types, because you need co-variance for reading (out) and contra-variance for writing (in).