Broken array covariance
Tags: csharp, java, array, covariance
Published: 2019-06-28 15:16:12

---
title: Broken array covariance
published: true
description: 
tags: #csharp #java #array #covariance
---

<i>Array covariance is broken?</i> Yes it is!

The code examples I show here applies to C# and it applies to Java as well, because I think Java was the first to make(break?) this. C# unwillingly had to do the same in its language.

Variance (Covariance, contravariance, invariance) is a hard topic to explain. But I am going to try anyway. 

When designing a language with types, the designers must set certain rules about how types and its related types are substitutable. Any operation dealing with types is subjected to those rules. An operation could be covariant, contravariant or invariant. Note that an operation could not just be a function/method, but could also be an assignment. 

Consider these classes. <code>Small</code> and <code>Little</code> are both subclasses of <code>Big</code>.

```csharp
public class Big
{
}

public class Small : Big
{
}

public class Little : Big
{
}
```

If I can assign a <code>Small</code> type to a <code>Big</code> type, then that assignment operation was covariant with those types. 

```csharp
Big a = new Small();
Big b = new Little();
```

The converse is not true for the above operation. Contraviance is the converse of covariance. Covariance feels more intuitive than contravariance. The assigment operation is not contravariant with those types. If you try to do this, the compiler should warn you, because the rules of variance are well defined.

```csharp
Small s = new Big();
```
These are very simplified examples. If you would like me to cover this topic elaborately in another post, please let me know in the comments.

In this post I am going to talk only about broken array covariance. 

The language designers decided to make arrays covariant. The following code is perfectly compile-able.

```csharp
Big[] bigArray = new Small[10];
```

The above assigment operation is legal, because it obeys the rules of variance. 

Now consider the following code. We are using the <code>bigArray</code> defined in the previous code. This code also perfectly legal. Because a <code>Small</code> object is assignable to a <code>Big</code> type. It satifies the covariance rules. 

```csharp
bigArray[0] = new Small();
```
<code>Little</code> assigned to <code>Big</code> also follows the covariance rules.

```csharp
bigArray[1] = new Little();
```

Here's where things go wrong. The above code is still perfectly valid code. The poor compiler does not know that the runtime disagrees.

If you run the program, it will end up with an exception trying to assign <code>Little</code> to <code>Big</code>. This is why the array covariance is broken. The problem is, even though the type is <code>Big</code>, the underlying storage is of <code>Small</code>. <code>Small</code> and <code>Little</code> are not substitutable with each other. 

Could the language designers have avoided this problem? May be. Let's create <code>List</code> instead of array. 

```csharp
List<Big> bigs = new List<Small>();
```

The above code does not compile. The problem is completely avoided by the compiler here to keep the types safe.

If you are working with array with related types, before inserting an object into an array, check its type first to avoid runtime errors. Next time when you are reviewing code with arrays, remember array covariance is broken!

Hope you found this interesting. Thank you for your attention.

Cheers :beer: