tags:

views:

207

answers:

2

In C#, I can compile

static class Foo<T> { /* static members that use T */ }

The result is generic and is not instantiable.

What is the equivalent F# code? module<'a> doesn't compile, and type Foo<'a> is instantiable.

+2  A: 

I thought at first that this would be close to what you wanted:

type Foo<'a> private() =   
    static member Blah (a:'a) =
       printfn "%A" a

Being like the idiom pre c# 2.0 of being instantiable only via reflection or by the class itself (which hopefully wouldn't do it).

however this is compiled down to:

[Serializable, CompilationMapping(SourceConstructFlags.ObjectType)]
public class Foo<a>
{
    internal Foo() {...}

    public static void Blah(a a) {...}
}

Which implies that other classes within the f# assembly could instantiate it.

However the ever informed Brian has indicated that the f# compiler respects this private setting despite the underlying CLR type which means that the only way to instantiate would be via reflection or by using something like the InternalsVisibleTo attribute.

This may still be acceptable for your needs...

ShuggyCoUk
Other classes cannot instantiate it; the constructor is 'private' to this F# type as far as F# is concerned.
Brian
ah - so f# respects the private over and above the actual .net CLR restrictions... InternalsVisibleTo would let it out of the bag to a c# assembly still though (not that I am indicating this is a flaw, just that it is possible with legal untrusted code). I'll update the answer cheers
ShuggyCoUk
+7  A: 

The other answers so far each have part of the picture...

type Foo<'a> private() =          // '
    static member Blah (a:'a) =   // '
        printfn "%A" a

is great. Disregard what Reflector generates, you cannot instantiate this class from within the F# assembly (since the constructor is private), so this works well.

F# does allow static constructors as well, the syntax is to include 'static let' and 'static do' statements in the class (which work analogously to how 'let' and 'do' work as part of the primary constructor body for instances). A full example:

type Foo<'a> private() =             // '
    static let x = 0
    static do printfn "Static constructor: %d" x
    static member Blah (a:'a) =      // '
        printfn "%A" a

//let r = new Foo<int>() // illegal
printfn "Here we go!"
Foo<int>.Blah 42
Foo<string>.Blah "hi"
Brian
love the //' trick will do that from now on
ShuggyCoUk