Type constraints for static methods

f#

Solution

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.

Problem

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() ```

Original source