Units of measurement in F#

One of the major advantages of static typed programming languages is the detection of type specific errors during implementation time. This early detection of errors may save time and money. Such type checks during implementation time are also possible for programming languages with dynamic type systems. But of course in such languages it is more difficult and sometimes even impossible to do such type checks.

Nevertheless, even if a strong type system is used, you cannot be sure to prevent type specific errors. For example, one typical source for errors may be the undefined usage of units of measurement, especially in development teams distributed over different countries.

One example for this issue is the loss of the NASA orbiter which was caused by a metric mismatch. One engineer team has used English units of measurement while the other one has used a metric system. This mismatch was resulting in a fault in one of the key spacecraft operations and the NASE lost the $125 million Mars orbiter.

Some programming languages will help to provide such errors. The F# programming language for example has support for static checking and inference of units of measurement. This will allow you to distinguish between two variables with the same type but different units.

 
Introduction

In F# it is possible to define units of measurement for floating point and signed integer values. Typically they are used to indicate things like length, volume, mass, and so on. By using these units the compiler can verify that arithmetic relationships have the correct units. This will help to prevent programming errors.

The following syntax is used to define units: [<Measure>] type myUnit;

The example code in this article shows some little calculations where the speed of vehicles is measured in kilometers per hour and meters per second. Therefore, at first, I have to create these four units of measurement.

[<Measure>] type m;     //meter
[<Measure>] type km;    //kilometer    
[<Measure>] type s;     //second
[<Measure>] type h;     //hour

At next it is possible to create some values and use the units of measurement. These units are used within brackets. The third value already demonstrates an easy calculation where the speed is calculated by a given way and time.

let speedOfCar = 55.0<km/h>
let speedOfBicycle = 10.0<m/s>
let speedOfMotorcycle = 30.0<km> / 0.5<h>

The F# Interactive view shows the following execution result:

val speedOfCar : float<km/h> = 55.0
val speedOfBicycle : float<m/s> = 10.0
val speedOfMotorcycle : float<km/h> = 60.0

 
Of course it is also possible to create some more difficult calculation where different units are used. The following source code shows some example where a distance is calculated by a given speed and time. Furthermore all distances should be shown in kilometer. Therefore the speed of the bicycle, given in meters per second, must be converted into kilometer per hour.

let speedOfCar = 55.0<km/h>
let speedOfBicycle = 10.0<m/s>

let distanceCar = speedOfCar * 1.5<h>
let distanceBicycle = speedOfBicycle * 1.5<h>
let distanceBicycleInKm = speedOfBicycle * 1.5<h> * 3600.0<s/h> / 1000.0<m/km>

The F# Interactive view shows the following execution result:

val speedOfCar : float<km/h> = 55.0
val speedOfBicycle : float<m/s> = 10.0
val distanceCar : float<km> = 82.5
val distanceBicycle : float<h m/s> = 15.0
val distanceBicycleInKm : float<km> = 54.0

 
Unit check and conversion

If the units of measurement don’t match, the compiler will show an error message. The following example shows a calculation where a sum of two values with the same type (double) but with different units should be calculated.

let speedOfCar = 55.0<km/h>
let speedOfBicycle = 10.0<m/s>

let speedDifference = speedOfCar - speedOfBicycle  

The F# Interactive view shows the following error:

error FS0001: The unit of measure ‚m/s‘ does not match the unit of measure ‚km/h‘

 
To solve this error you may create a convert function. The following source code shows an according example. In line 4 the convert function is implemented with a function parameter with defined units of measurement. In line 5 you see the same function but with a generic definition for the unit. In this case the unit of measurement will be determined by the function parameter. This feature may be useful e.g. for higher order functions.

let speedOfCar = 55.0<km/h>
let speedOfBicycle = 10.0<m/s>

let convertToKmH (value:float<m/s>) = value * 3600.0<s/h> / 1000.0<m/km>
let genericConvertToKmH (value:float<_>) = value * 3600.0<s/h> / 1000.0<m/km>

let speedDifference = speedOfCar - convertToKmH speedOfBicycle

 
Convert between values with or without units

A value without units of measurement may be easily converted to a value with units. In such a case you can multiply this value with a dummy value which is 1 and has units. The following example shows an according conversion.

let standardFloat = 55.0
let speedOfCar = standardFloat * 1.0<km/h>

 
A conversion back can be done in the same way by divide with an dummy value.

let speedOfCar = 55.0<km/h>
let standardFloat = speedOfCar / 1.0<km/h>

 
For interoperability, there are also some explicit functions that you can use to convert values with and without units. These functions are in the module Microsoft.FSharp.Core.LanguagePrimitives.

let standardFloat = 55.0
let speedOfCar:float<km/h> = LanguagePrimitives.FloatWithMeasure standardFloat

 
Performance

One important question is, whether the use of units of measurement influences the performance of you application because these additional unit checks must be done. The pleasant news is, there is no influence on the execution speed of your application. Units of measurement are used only during compile time. Unit checking is not persisted in the runtime environment. Therefore, they do not affect performance.

 
Summary

With units of measurement the F# languages offers a nice feature to prevent type unit errors. With a little overhead during implementation time (you have to write down the units) you will save a lot of effort during testing and bug fixing phases. Furthermore the use of units of measurement may prevent cost-intensive bugs like the loss of the NASA orbiter.

Advertisements
Dieser Beitrag wurde unter .NET, F# abgelegt und mit , , verschlagwortet. Setze ein Lesezeichen auf den Permalink.

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s