I am using OpenTK with its math library but unfortunately there is no generic interface for the vector classes. For example Vector2 ,3 and 4 all have the same static method SizeInBytes
http://www.opentk.com/files/doc/struct_open_t_k_1_1_vector3.html#ae7cbee02af524095ee72226d842c6892
Now I could just overload tons of different constructors but I think it should be possible to solve this via type constraints.
I was reading though http://msdn.microsoft.com/en-us/library/dd233203.aspx and I found this
type Class4<'T when 'T : (static member staticMethod1 : unit -> 'T) > =
class end
Now I have tried it by myself but I can't get the syntax right.
type Foo<'T when 'T: (static member SizeInBytes: unit -> int)>(data: 'T []) =
member this.GetBytes() = 'T.SizeInBytes()
let f = Foo([|new Vector3(1.0f,1.0f,1.0f)|])
f.GetBytes()
Can you spot the problem?
Edit:
VS2012 complains about this line 'T.SizeInBytes() //Unexpected symbol or expression
and T.SizeInBytes()
doesn't work either.
Edit2:
I made an example that doesn't involve an external library
type Bar() =
static member Print() = printf "Hello Foo"
type Foo<'T when 'T: (static member Print: unit -> unit)>(data: 'T []) =
member this.Print() = 'T.Print()
let b1 = Bar()
let f = Foo([|b1|])
f.Print()
The correct syntax for calling things which are guaranteed by member constraints is a bit obscure:
type Foo< ^T when ^T: (static member SizeInBytes: unit -> int)>(data: ^T []) =
member inline this.GetBytes() =
(^T : (static member SizeInBytes : unit -> int) ())
Note that 'T
has to be changed to a "statically resolved type variable" ^T
- see the Glossary in the F# spec.
You can't call members specified by constraints on normal type variables, because that's not supported by the .NET framework, so F# has to compile them away. It's a syntax error if we try to use 'T
in GetBytes
instead.
I think the MSDN documentation is being a bit misleading by giving an example with 'T
, because although you can write the type they give, you could never use the constraint.
If you look at the IL code for the Class4
sample, the constraint is actually gone:
.class nested public auto ansi serializable Class4`1<T>
extends [mscorlib]System.Object
which makes sense because the member constraint has to be removed for .NET. The same is true for type Foo
with the ^T
type variable.
Note also that in common with all inline
F# functions, you can only call it statically from F# code, so that the compiler can inline the definition at the call site.
It will throw an exception if you try to call it from C# code, or via reflection. If you try, your code will fail at runtime.
Generally working with F# constraints that aren't supported by .NET is a tricky business, so I'd steer clear if at all possible.
EDITED: I've substantially updated my original answer which incorrectly said this wasn't possible, in light of (a) my further experiments (b) Gene Belitski's answer and (c) idjarn's comment that inline
functions always get compiled to IL that throws an exception.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With