Search code examples
f#units-of-measurementtype-extension

F# type extension with units of measure type conversion resulting in strange error


I have a function that converts from my own implementation of a 3D vector (which supports units of measure) to XNA's implementation:

type Vector3<[<Measure>]'a> with
    member inline v.ToXna() =
        Microsoft.Xna.Framework.Vector3(v.x / 1.f<_>, v.y / 1.f<_>, v.z / 1.f<_>)

When I compile it, I get a strange error:

The signature and implementation are not compatible because the type parameter in the class/signature has a different compile-time requirement to the one in the member/implementation

The inline seems to be a necessity; without it, I get this error:

This construct causes code to be less generic than indicated by the type annotations. The unit-of-measure variable 'a has been constrained to be measure 'm'.

Any idea what's going on?

Edit To answer @svick's questions, Vector3 is defined as:

type Vector3<[<Measure>]'u> =
    struct
        val x:float32<'u>
        val y:float32<'u>
        val z:float32<'u>
        new(x, y, z) = { x = x; y = y; z = z }
    end

And I'm also having some type inference problems defining it as a normal function:

let vector3 (v:DumpEngine.Vector3<_>) =
    Vector3(v.x / 1.f<_>, v.y / 1.f<_>, v.z / 1.f<_>)

Causes the function to be a Vector3<1> -> Microsoft.Xna.Framework.Vector3, which makes it quite unusable. I'm not sure this is a related issue, though.


Solution

  • I have no idea what's going on, but this seems to work:

    let inline ToXna(v:Vector3<'a>) =
        Microsoft.Xna.Framework.Vector3(v.x / 1.f<_>, v.y / 1.f<_>, v.z / 1.f<_>)
    

    It's the best I managed to do, though.