Search code examples
f#generic-programming

Generic class with a measure constraint


How do I create a generic class in F#, with a constraint that the type is a measure?

I've tried this but a2 and b2 do not produce errors:

open Microsoft.FSharp.Data.UnitSystems.SI.UnitNames

type Vector2D_A<[<Measure>] 'u>(x : float<'u>, y : float<'u>) =
    member this.X = x
    member this.Y = y

type Vector2D_B<'t, [<Measure>] 'u>(x : 't, y : 't) =
    member this.X = x
    member this.Y = y

type Vector2D_C<'t>(x : 't, y : 't) =
    member this.X = x
    member this.Y = y

let a1 = Vector2D_A(1.0<metre>, 2.0<metre>)
let b1 = Vector2D_A(1.0<metre>, 2.0<metre>)
let c1 = Vector2D_C(1.0<metre>, 2.0<metre>)

let a2 = Vector2D_A(1.0, 2.0) // should produce an error
let b2 = Vector2D_A(1.0, 2.0) // should produce an error
let c2 = Vector2D_C(1.0, 2.0)

I would like to define a class like any of these three examples (but they do not compile):

1)

type Vector2D_B<'t, [<Measure>] 'u>(x : 't<'u>, y : 't<'u>) =
    member this.X = x
    member this.Y = y

2)

type Vector2D_B<'t when 't :> 't<[<Measure>]>>(x : 't<'u>, y : 't<'u>) =
    member this.X = x
    member this.Y = y

3)

type Vector2D_B<'t when 't :> 't<_>(x : 't<'u>, y : 't<'u>) =
    member this.X = x
    member this.Y = y

Solution

  • Writing 't is equivalent to writing 't<1> - where <1> represents the unit of measure for dimensionless values, which applies implicitly when no other unit of measure is explicitly provided.

    Consequently, you can't force the compiler to produce an error message when you don't explicitly provide a unit of measure, since when you do that you're implicitly providing the unit of measure for dimensionless values.