Ruminations on a system of units of measure in Scala, Part 1: Presented Without Comment

I was wondering the other day – how much does it cost to fill a swimming pool with beer?

So I wrote a short program to find out.

val length = 50 metres
val width = 25 metres
val depth = 9 feet
val swimmingPool = length * width * feet

val costOfAPint = (3.50 pounds) / (1 pints)

println(f"It would cost £${(swimmingPool * costOfAPint) in pounds}%10.2f to fill a swimming pool with beer")

This is, of course, a hugely inefficient way of filling a swimming pool with beer – which, regardless of methodology, is a task of dubious merit in the first place. On the other hand, it’s a decent way to demonstrate my units of measure library for Scala.

The library povides two basic functions: it provides transparent conversions between different units, and checks dimensions to ensure that any operations are valid. For example, if you want to know how many gallons there are in an inch of rainfall on a hectare:

println(s"An inch of rainfall on a hectare is ${(1 hectares * 1 inches) in gallons} gallons of water")

But if you forget the inches:

println(s"An inch of rainfall on a hectare is ${(1 hectares) in gallons} gallons of water")

Well, then, that’s an error. What type of error depends on which version of the library you’re using: there’s a dynamic and a static implementation. The static version would give you a type error at compile time, whereas the dynamic version would give you a DimensionMismatchException at runtime.

Obviously, these code snippets are extracts, not full programs – the full swimming pool program (using the dynamic library) reads as follows:

import com.writeoncereadmany.unitsofmeasure.dynamictypes.units.Sterling._
import com.writeoncereadmany.unitsofmeasure.dynamictypes.units.Length._
import com.writeoncereadmany.unitsofmeasure.dynamictypes.units.ImperialLength._

object DynamicSample
{
  def main(args: Array[String])
  {
    val length = 50 metres
    val width = 25 metres
    val depth = 9 feet
    val swimmingPool = length * width * depth

    val costOfAPint = (3.50 pounds) / (1 pints)

    println(f"It would cost £${(swimmingPool * costOfAPint) in pounds}%10.2f to fill a swimming pool with beer")
  }
}

A statement like val length = 50 metres will give you a Quantity, which knows both how big it is (50 metres) and what dimensions it has (length). You can perform arithmetic on it (add/subtract it from other Lengths – trying to add or subtract it from, for example, an Area or a Time would result in an error), but in order to get a numeric value back out of it, you need to specify what units you want (and if the units don’t match the quantity, you get an error).

All you need to use the library is to import the appropriate dimension objects. Length, for example, includes a selection of units of length (including metres and feet), units of higher-order lengths (such as areas, volumes – including pints), and the implicit conversions to allow declarations like 50 metres.

In order to extend the library – to add your own units, for example – you need to know a little about how it works. That’s coming in part 2…

Advertisements

5 thoughts on “Ruminations on a system of units of measure in Scala, Part 1: Presented Without Comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s