Covariance and contravariance - simple explanation

This is a very concise tutorial on covariance and contravariance. In 10 minutes you should understand what these concepts are and how to use them. The examples are in Scala, but apply to Java or C# as well.

Covariance

Assuming Apple is a subclass of Fruit, covariance lets you treat say List[Apple] as List[Fruit].

val apples = List(new Apple(), new Apple())
processList(apples)

def processList(list:List[Fruit]) = {
  // read the list
}

This seems obvious - indeed, a list of apples is a list of fruit, right?

The surprise comes when we find out this does not work for arrays. Why is that so? Because you could do the following:

val a = Array(new Apple(), new Apple())
processArray(a)

def processArray(array:Array[Fruit]) = {
  array(1) = new Orange() // putting an Orange into array of Apples!
}

The main difference between List and Array here is that the List is immutable (you cannot change its contents) while the Array is mutable. As long as we are dealing with immutable types, everything is OK (as in the first example).

So how does the compiler know that List is immutable? Here is the declaration of List:

sealed abstract class List[+A]

The +A type parameter says "List is covariant in A". That means the compiler checks that there is no way to change contents of the List, which eliminates the problem we had with arrays.

Simply put, a covariant class is a class from which you can read stuff out, but you can't put stuff in.


Contravariance

Now when you already understand covariance, contravariance will be easier - it is exactly the opposite in every sense.

You can put stuff in a contravariant class, but you can never get it out (imagine a Logger[-A] - you put stuff in to be logged). That doesn't sound too useful, but there is one particularly useful application: functions. Say you've got a function taking Fruit:

// isGoodFruit is a func of type Fruit=>Boolean
def isGoodFruit(f:Fruit) = f.ageDays < 3

and filter a list of Apples using this function:

val list:List[Apple] = List(new Apple(), new Apple())
list.filter(isGoodFruit) // filter takes a func Apple=>Boolean

So a function on Fruits is a function on Apples - the filter will throw Apples in and isGoodFruit will know how to handle them.

The type of isGoodFruit is actually Function[Fruit, Boolean] - yes, in Scala even functions are traits, declared as:

trait Function[-A,+B]

So functions are contravariant in their parameter types and covariant in their return types.

OK, that's it; this is the minimal explanation I wanted to cover.

Posted by Martin Konicek on 11:39 PM 18 comments

Software engineering radio - best episodes

Software engineering radio is an excellent podcast full of in-depth information for developers; contains high quality content different from what you usually find online.

General

NoSQL and MongoDB with Dwight Merriman
Top 10 Architecture Mistakes with Eoin Woods
Being a consultant - honest, informal and funny
Software Craftsmanship with Bob Martin - concentrated motivation
Stefan Tilkov on REST - quite practical
Singularity research OS - microkernels, safety, static code analysis

Scala

Martin Odersky on Scala - great interview with the author of Scala
Scala Update with Martin Odersky - second half provides insights into possible future of programming

OmegaTau


Btw, Markus Völter (the guy behind se-radio) also does a podcast on technology and science. Software engineer talking to a Nuclear fusion expert - what could we want more? ;) I really enjoyed the following episodes:

Astrobiology at the NASA Astrobiology Institute
Quantum computing - kudos for mentioning the "next technical revolution"
Nuclear Fusion at MPI für Plasmaphysik



Please help me find great episodes - if you know about an episode that you really enjoyed, post it into comments. Thanks!

Posted by Martin Konicek on 2:00 PM 15 comments

TFS addin for Outlook TaskConnect released!

TaskConnect connects Outlook with issue tracking systems in a very cool way. So far there is support for TFS (2008, 2010) and Redmine.

This is how TaskConect looks inside Outlook:



It has many useful concepts making you deal with your tasks in no time. Be sure to check out the entirely new website.

Posted by Martin Konicek on 12:08 AM 2 comments

Scripting in Scala

Imagine we have a long text file, for example:

'CHINESE' : 'zh',
'DUTCH': 'nl',  
'ENGLISH' : 'en',
'SPANISH' : 'es',

And we want to turn it into this:

'zh' : 'Chinese',
'nl' : 'Dutch',  
'en' : 'English',
'es' : 'Spanish',

What we want to do is very simple: "Swap the two parts on every line!", and I believe it should be this simple also in code. Let's see how it looks in Scala:

import scala.io.Source

val lineRegex = "\\s+'(.+)'.*'(.+)'.*".r

for(line <- Source.stdin.getLines) {
   val lineRegex(name, code) = line
   println("'%s': '%s'," format (code, name.toLowerCase.capitalize))
}

That's 5 lines including the import, and the code is readable. Now we can run:

cat languages.txt | scala ourScript.scala > output.txt

That's it.

Btw, let's look at at the options we had for solving the problem:
  1. We don't want to be writing code in Java, C++ or C# and actually compiling an executable. Also you can imagine that the code in any of these languages would be overly complicated.
  2. OK, so we definitely should use a scripting language. What options do we have?
    • sed, awk, perl - Learn a (cryptic) language just for the purposes of scripting? No thanks.
    • Python, F#, Scala - All these languages have an amazing property that while you are already building your applications in them, you can use them for writing quick scripts. Scala is just elegant and more innovative than F# or Python. For a deeper look how the magic with lineRegex works, see this. If unfamiliar with Scala, here is a quick overview.

Posted by Martin Konicek on 4:02 PM 2 comments

Posted by Martin Konicek on 6:46 PM 5 comments

New blogposts about programming Outlook add-ins

I published two new blogposts on the website of our add-in for Outlook called TaskConnect:
Adding custom data to Outlook emails
Searching emails from an Outlook add-in

Knowing the information published there before developing TaskConnect would definitely help me a lot so I'm sharing it. I hope you will also find it useful.

Posted by Martin Konicek on 12:00 AM 4 comments

TFS addin for Outlook TaskConnect goes live!

You can download the first beta of TaskConnect now. I've been working on this for the last year with a team of cool guys in Prague.
TaskConnect is quite unique as it integrates TFS into Outlook in a new, clever way:

  • TaskConnect is a full-fledged TFS client with fulltext search field at your fingertips right in Outlook
  • Work items can be attached to emails: when you are discussing a work item with someone, the work item is visible right next to the email throughout your whole conversation. You can of course edit it right from Outlook.
  • Saving your time is absolutely the primary goal - speed of use is just incomparable to any existing TFS client
We think this is such a good idea that it would be silly just to support TFS. So in the future you can expect Outlook integration of many popular issue tracking systems. We also have a ton of ideas for the future and we are looking forward to your feedback and ideas.

Posted by Martin Konicek on 4:50 PM 0 comments