Its been a little time since the last post, but I always resolved to finish this series, so here we go with Episode 7.
The subject of Variance in computer science is well documented and well described and you’ll find scores of articles on the subject if you cared to enter the term into your favourite search engine. I’ve included a selection of links at the bottom which may assist you in further reading.
So, why write another series on this when there’s so many already? Well, unfortunately, I Just Didn’t Understand then. Let’s be clear on this, I found Covariance and Contravariance hard to comprehend to any level on which I was satisfied, and, sometimes the best way of understanding anything to try to explain it to someone else1. In fact, the ‘someone else’ in question is a colleague of mine, James who might be a little surprised when he reads this.
The term Variance in relation to computing has its root in the mathematical area of Category Theory2. The challenge is to convey the language of this domain to those who have never studied or even heard of it.
So, this article will try to describe these topic from a novice programmer’s perspective. It’s also important to note that the explanation won’t be entirely correct, but it’ll do for now.
We’ve spoken at length about Casting and the notion of Assignment Compatibility. Generally speaking, the former can be achieved if the latter is met. More profoundly, Casting is an operation, whereas Assignment Compatibility describes a relationship. This is exactly what the terms Covariant and Contravariant do – they describe a Relationship.
The previous articles had hinted at Variance as a future topic, with the message “we’re not quite there yet”, however that was a lie, because Assignment Compatibility is a special kind of Variance. If we can understand our rules for the former we find it easier to grasp the latter.
But, whereas Assignment Compatibility describes the relationship between two related Types, Variance describes the relationship between two ‘Wrappers Of‘ different types. To understand what we might mean by ‘Wrappers Of‘, simply replace the word ‘Wrappers‘ with a C# collection of your choice. For example:
- Variance describes the relationship between two ‘Lists‘ of different Types3.
- Variance describes the relationship between two ‘Arrays‘ of different Types.
Although the above implies collections, we can also talk about Delegates and Interfaces, which aren’t strictly speaking ‘Collections Of‘, but can certainly be ‘Wrappers Of‘ the Types.
In short, Variance describes the relationship between an instance of a “Thing that Wraps a Type“, and another instance of an “identical Thing that Wraps a different Type.”
Whilst, in theory, Variance describes the relationship between any such ‘Wrappers Of‘ two different types, in reality C# limits the ‘Wrappers Of‘ to three particular areas:
- Generic Interfaces
We’ll cover them in more detail later, but its enough to highlight currently that Lists, Dictionaries, and other strongly typed collections do not support Variance, and the same is true for most Return Types and Function Parameters. Again, we’ll visit this a little later.
Finally its worth stating up front the different kinds of variance we can perceive. Relationships between two identical things that wrap different types can be described as:
We’ll leave it at that for the moment, and leave the description of these to later posts. And with that…
Next up – Types of Covariance…
1 My friend, Ian Ozsvald reckons that presenting on a topic is the best way of refining knowledge. In this respect, I would include “writing” as a form of presentation.
2 The term Variance is also used in Statistical and Probability Theory, which is different.
3 There is no variance on the generic List type in C#. I just wanted to get across a concept.