Quote of the week – type systems and unit tests

A type system is the most cost effective unit test you’ll ever have.

Peter Hallam

Peter Hallam was a language designer on the first three versions of C#, then became technical lead for the C# compiler before moving to Google and building the Traceur compiler which compiles JavaScript.next to standard JavaScript. If you want to hear him talk about Traceur checkout this video.

Peter’s a man who knows his type systems – good, bad and ugly.

I saw a nice example of using the type system to prevent bugs when I worked on Pixel Bender at Adobe. Pixel Bender is an image processing toolkit. Images are made up of pixels, however, pixels are not always 1×1 in size, and they are not always square – in particular, video processing often uses rectangular pixels. At the time we started the project we hadn’t come to grips with non-square, non-unit-sized pixels so we started with a single coordinate system where moving right one unit moved you one pixel across, and moving up one unit moved you one pixel up. This pixel coordinate system is not isotropic – one unit on the X axis is not necessarily the same distance as one unit on the Y axis. We wanted to be able to represent rectangular areas of pixels so we created two classes – Position (containing x and y values) and Extent (containing width and height values).

We got away with our pixel coordinate system for quite a long time, however eventually we realized that we needed to have an underlying, isotropic, coordinate system. We called this world coordinates. We converted between pixel coordinates and world coordinates by using the width and height of a single pixel. Since we already had Position and Extent classes we used them for our world coordinate system as well.

Imagine you see a function that takes a Position as an input parameter. Is that Position in world coordinates or pixel coordinates? We instituted some naming conventions. They sort of worked. Mostly. Except when they didn’t. We had plenty of tests, which caught some of the bugs, but working with a Position or an Extent was more fragile than we wanted.

Our solution was to create separate classes for pixel and world coordinates. We ended up with:


The two Position classes were identical apart from their name, as were the two Extent classes. In both cases we just had the simplest possible wrapper around two double values with appropriately named accessor methods. We could have used some template magic to avoid code duplication. We could have used some “clever” macros (and I put “clever” in quotes to indicate my disdain). We actually just wrote separate classes – very simple classes, with some repetition of boilerplate between them. Breaking the normal “don’t repeat yourself” rule seemed justified here. For a little (and it really was a little) more work up front we had a very simple system that served us well. If we had been working with tens or hundreds of different coordinate systems we might have used another method to generate the code, but we only had two, and we were relatively convinced that we were never going to add more than one or two additional coordinate systems (as it turned out we only needed pixel and world coordinates).

By looking at code you knew what coordinate system was in use. When writing new code you could specify what coordinate system it needed its inputs to be in. If you tried to pass a value in the wrong coordinate system to a function the compiler would stop you. The system worked. We made it easier to do it right than to do it wrong – using the type system eliminated a whole class of bugs from our code.

5 thoughts on “Quote of the week – type systems and unit tests

  1. Great! I often see legacy code which is technically avoids the type system and (almost) only uses the built in types. I think this is because a lot of people see an average type system as a contract to satisfy and not a tool to easily model ideas and let the compiler do the hard work. Scott Wlaschin did a great presentation in London last year about this topic, you may find it interesting: http://www.slideshare.net/ScottWlaschin/ddd-with-fsharptypesystemlondonndc2013

  2. John Payson says:

    A major limitation with many type systems is that they tend to characterize things based upon how they are stored, rather than what they represent. In Java or in .NET languages, a variable of type `int[]` will hold either `null` or a reference to an array of integers, and that’s all the compiler will know or care about. Semantically, however, a variable of type `int[]` may represent at least four very different things:

    1. A reference to an array whose contents will never change and may be freely shared among things that promise not to modify it.

    2. The only reference, anywhere in the universe, to an array which is exclusively owned by the owner of the reference, and which may be freely modified as the owner sees fit.

    3. A “non-owning” reference to an array which is owned by some other entity.

    4. A reference to an array which is owned by the owner of the reference, but to which other entities also have “non-owning” references.

    In the first two situations, the reference is used to encapsulate the *content* of the array; in the third, it encapsulates *identity only*, and in the fourth it encapsulates *identity and content*.

    Nothing in the type system distinguishes among the four usages, but I would posit that the semantic differences between them are more significant than the differences between e.g. an `int[]` and a `long[]`. A compiler would need to be able to distinguish the latter types to generate correct code, of course, but semantically the differences among the different kinds of `int[]` (or among the corresponding different kinds of `long[]`) are more singificant than those between `int[]` and `long[]`, even though neither Java nor .NET includes any means of expressing them, and the widespread hatred of apps Hungarian has prevented even that from being used as a means of distinction.

Leave a Reply

Your email address will not be published. Required fields are marked *