Type-safe physical unit representation

When developing games, working with positions and velocities, time stamps and time spans and similar physical quantities becomes second nature to us.

I would like to explore how we can represent the physical nature of these values, and their relation to each other in code.

The problem with using one type for multiple kinds of values

In a semantic sense there is a big difference between a position and a velocity, or between a time stamp and an object’s speed.

However, regardless of the semantic difference, we tend to implement all these types of values as simple floating point numbers, or vectors of the same. That means that in terms of the code we write there is no difference between values that clearly represent vastly different physical concepts.

This can lead to a number of bugs, mostly caused by thinkos – small mistakes in thinking – or even typos. For example, in most games, any of the following lines of code would be perfectly valid inside an object’s update method.

this.position = this.velocity;

this.angle = currentTime;

this.position = this.position + this.velocity;

The first two are nonsense, and it is easy to see why. The last however, might look all right at a glance: We are moving the object by adding its velocity to its position.

However, even the third line is likely to be wrong in the vast majority of games. Fixed frame rates are – mostly – a thing of the past, and instead of storing velocity in translation per frame, we usually use easier units like translation per second.

The correct line of code would then be:

this.position = this.position + this.velocity * deltaTime;

What is even worse than the possibility of this bug however, is that we might never catch it before it gets into the hands of our players. Maybe we as developers only test our own game – at this part of it – at 60 FPS, so we might never know that our objects move with different speeds based on the frame rate.

We can be sure however, that players with particularly weak or powerful hardware will discover this bug before long, which might cause them to walk away from our game forever, if it feels broken.

Using distinctive types for semantic values

So what can we do about this?

What causes this problem is that we use the same type for very distinct kinds of values so that there is no possible way of checking for what operations between them are allowed, and what kind of value they return.

The – or at least one – solution follows easily: We need to use different types to represent values with semantically different meanings and only allow for valid operations between them.

For example, let us say we implement the types Vector, Velocity, Acceleration and Time with their units as follows.

Type Unit Unit Example
Vector distance meters
Velocity distance/time meters/second
Acceleration distance/(time*time) meters/(second * second)
Time time second

With these units, we could (among others) define the following operators:

Vector + Vector -> Vector
Velocity + Velocity -> Velocity
Velocity * Time -> Vector
Acceleration * Time -> Velocity

And with these operations we could write our code above:

class MyObject
{
    private Vector position;
    private Velocity velocity;

    public void Update(Time deltaTime)
    {
        Acceleration a = this.getAcceleration();

        this.velocity += a * deltaTime;
        this.position += this.velocity * deltaTime;
    }
}

Note that since we only defined operators that make sense semantically – and in this case physically – we know for a fact that all the types in the above code check out. If they would not – for example if we tried to add a velocity to a position vector – we could get a compile time error and our game would not start until we fix the problem. Equivalently, assuming that we only define physically valid operators, the physical units of all our values and operations will be well defined, and always be valid and clear.

While the additional amount of effort may seem annoying at first, it means that we will catch the above kinds of errors directly while writing our code (especially with a good IDE), and do not have to waste our time compiling, running, and testing it.

In addition, using types like this can make it significantly easier for us to work with code – both other’s and our own – in the first place. It completely removes questions like ‘Does this value represent an instant in time, or the speed of the object?’ or ‘Does this method expect a position or velocity?’.

Further, we are forced to consider our own code more carefully. Since only valid operators between the types are allowed, we cannot use any hacks or short-cuts – which may be unclear to others or even error prone – without explicitly converting our input to type-less – or unit-less – values. In other words, we cannot accidentally – or on purpose – write physically nonsensical code without making that fact explicit to potential readers.

Conclusion

As it happens, I have been working on and with types like the ones I propose here for some time now.

While the jury is still out on whether I prefer this approach over the one using pure floating point values and vectors, my experience so far is very positive.

Note that to make this system as easy to use as the other approach – after all, we do not want to have to write significantly more code – I had to add a few more types than mentioned in this post. And of course, the number of operators between the different types is vastly larger.

For a full list of types and their relationships, make sure to check my follow up post.

If this post has been interesting to you, make sure to share it on your favourite social media.

And of course feel free to leave a comment with questions or other feedback.

Enjoy the pixels!

Leave a Reply