3 ms·
You can certainly annotate 3rd-party libraries. You basically just copy the signatures of the relevant APIs, and decorate arg types and return types with units
by latkin 12y ago
You can certainly annotate 3rd-party libraries. You basically just copy the signatures of the relevant APIs, and decorate arg types and return types with units that enforce the semantics of the problem domain.
Say you have some unit-free external library like this, which you can't modify:
type RectLib =
static member Perimiter(w:int, h:int) = 2*w + 2*h
static member Area(w:int, h:int) = w * h
Wouldn't it be great if we could enforce in our code that `w` and `h` have the same units? Or that the result of `Area` has squared units compared to the result of `Perimiter`?
You can do exactly that, by defining extensions like so:
module UnitExtensions =
open LanguagePrimitives
type RectLib with
static member Perimiter(w:int<'u>, h:int<'u>) =
RectLib.Perimiter(int w, int h) |> Int32WithMeasure<'u>
static member Area(w:int<'u>, h:int<'u>) =
RectLib.Area(int w, int h) |> Int32WithMeasure<'u^2>
Now units are enforced by the type system:
open UnitExtensions
RectLib.Perimiter(1<m>, 2<ft>) // error - <m> doesn't match <ft>
RectLib.Perimiter(3<m>, 4<m>) // ok
RectLib.Area(5<m>, 6<m>) + RectLib.Perimiter(7<m>, 8<m>) // error - <m> doesn't match <m^2>
RectLib.Area(9<ft>, 10<ft>) + RectLib.Area(11<m>, 12<m>) // error - <ft^2> doesn't match <m^2>
RectLib.Area(9<ft>, 10<ft>) + RectLib.Area(11<ft>, 12<ft>) // ok