Scott Nimrod
Scott Nimrod

Reputation: 11595

When should I NOT use Units of Measure?

When should I NOT use Units of Measure?

I feel that any values that are used in calculations should have a unit of measure applied to it.

Are my thoughts accurate?

If they are, then why doesn't F# by default enforce this constraint to encourage correctness?

In my case, I used Units of Measure for a basketball game:

For example:

[<Measure>] type pts
type Player = { Score:int<pts> }

Here's the model that leverages units of measure:

(*Types*)
[<Measure>] type pts
type Player = { Score:int<pts> }

type FieldShot = TwoPointer| ThreePointer
type FoulShots = FoulShot  | TwoFoulShots | ThreeFoulShots

type FoulShooter  = FoulShooter  of Player
type FieldShooter = FieldShooter of Player

(*Functions*)
let shoot (lastShot:int<pts>) player =
    (player.Score + lastShot)

let fieldShot (fieldShooter, shot) =

    let player = match fieldShooter with
                 | FieldShooter player -> player

    match player.Score with
    | score when score > 10<pts> -> score
    | _ ->  match (fieldShooter, shot) with
            | FieldShooter player, shot -> match shot with
                                           | TwoPointer   -> player |> shoot 2<pts>
                                           | ThreePointer -> player |> shoot 3<pts>
let foulShot (foulShooter, shot) =

    let player = match foulShooter with
                 | FoulShooter player -> player

    match player.Score with
    | score when score >= 11<pts> -> score
    | _ ->  match (foulShooter, shot) with
            | FoulShooter player, shot -> match shot with
                                          | FoulShot       -> player |> shoot 1<pts>
                                          | TwoFoulShots   -> player |> shoot 2<pts>
                                          | ThreeFoulShots -> player |> shoot 3<pts>

let makeFoulShots foulShots (shooter, defender) = 
    FieldShooter { Score= foulShot (shooter, foulShots) }, defender

let makeFieldShot fieldBasket (shooter, defender) =
    FoulShooter { Score= fieldShot (shooter, fieldBasket) }, defender

let turnover (shooter, defender) = (defender, shooter)

(*Client*)
let player1, player2 = FieldShooter { Score=0<pts> } ,
                       FieldShooter { Score=0<pts> }

let results = (player1, player2) |> makeFieldShot TwoPointer
                                 |> makeFoulShots ThreeFoulShots
                                 |> makeFieldShot TwoPointer
                                 |> makeFoulShots TwoFoulShots
                                 |> makeFieldShot TwoPointer
                                 |> makeFoulShots FoulShot

Upvotes: 1

Views: 224

Answers (2)

TheInnerLight
TheInnerLight

Reputation: 12184

Well, the only answer that springs to mind is that you should generally not use unit of measures for dimensionless quantities.

Consider values such as pi or e.

Dimensionless values often arise from ratios of quantities that do have some physical dimension.

Consider you want to create some program logic that triggers when one team's basket ball score reaches double the score of another team, you would need a dimensionless quantity:

if teamBScore >= 2 * teamAScore then
    ...
else
    ...

The value 2 has to be used in a calculation and has to be dimensionless or the units of teamAScore and teamBScore wouldn't match.

Of course, strictly speaking you could annotate such values with units of 1 explicitly but that's probably overkill.

Aside from that, the rest of the question is primarily opinion based. You should use or not use units of measure depending on how you assess the gain in safety you'll get at the cost of (slightly) increased programming time and verbosity.

Upvotes: 3

Alexey Romanov
Alexey Romanov

Reputation: 170745

If they are, then why doesn't F# by default enforce this constraint to encourage correctness?

For one, because it needs to interoperate with languages which don't support units of measure. If you want to use values coming from a C# library method in a computation, how can it decide what unit to use? Even if F# developers spend a lot of time annotating all the standard library methods with units of measure, this wouldn't help with third-party libraries.

Upvotes: 2

Related Questions