I have defined a record type with a unit of measure in a common library (LibRoot) that is used by both C# (LibC) and F# (LibF) code.
I then wrote a public API in the C# library (LibC) that the F# library (LibF) consumes. But any time i attempt to pass an object to this API F# complains that it must have a unit of measure.
//LibRoot - F#
type Vec2<[Measure] 'u> = {
X : int
Y : int
}
//LibC - C#
public static class Funcs
{
public void DoWork(Vec2 vec) { //no measure needed in C#
....
}
}
//LibF - F#
open LibC
let myVec : Vec2<1> = { X = 123; Y = 456 }
DoWork(myVec) //FS0001
error FS0001: Type mismatch. Expecting a 'Vec2' but given a 'Vec2<1>' The tuples have differing lengths of 0 and 1
I've tried:
Vec2<1>
: FS0001Vec2<0>
: Invalid Literal in typeVec2<()>
: Unexpected ')' in typeVec2<_>
: FS0001Vec2<unit>
: Expected unit of measure, not type(Vec2) myVec
: No constructors available for type 'Vec2<'u>Does anybody know a way to construct a measured record type in an interop friendly way?
As mentioned in the comment, units of measure are F#-only feature that has no representation in the compiled .NET code, so when you use a unit-annotated type from C#, it will appear as a type without units.
The compiled C# code will not contain special F# meta-data to indicate that this is a unit-annotated type and so the F# compiler referencing your C# library does not recognise it as unit-annotated type. Arguably, the F# compiler could be smarter and figure this out (because it can figure out that the Vec2
type is originally coming from F#).
I don't think there is a safe way of converting un-measured Vec2
to measured Vec2<_>
but the unsafe conversion using unbox
will work at runtime:
let v : LibRoot.Vec2<1> = { LibRoot.Vec2.X = 1; Y = 2 }
LibCs.Funcs.DoWork(unbox v)
I don't think there is a way of referring to the type Vec2
(without measure) explicitly in F# code, but unbox
infers the type fine. This is not very nice, so if you need this conversion often, it's probably better to redesign your library so that C# uses a separate type without units.