FPguy
FPguy

Reputation: 127

F#: get source files to evaluate automatically

I'm making a project where there are separate source files/modules that add functions to a single Dictionary contained in a higher level file. However, I find that nothing in these source files evaluates on its own, even functions that take no arguments/code that isn't even inside a function.

As a result nothing is being added to the Dictionary. Is there a way to forcibly evaluate complete function calls in a module automatically? I'll give an example of what I'm trying to do:

Registry.fs:

let private functions = Dictionary<string, MessageHandler>()

let add type handler = 
    functions.Add(type, handler)

Handler1.fs:

Registry.add "type1" (fun m -> ....
)

Handler2.fs:

Registry.add "type2" (fun m -> ....
)

Upvotes: 3

Views: 66

Answers (1)

stackh34p
stackh34p

Reputation: 9009

I believe you need to see this relevant topic. Loose method calls would get compiled as method calls inside of a static constructor for the enclosing type/module, when the F# code gets compiled to IL. This would roughly be equivalent to the following C# code, just to see the picture:

static class Handler1 {
    static Handler1() {
        // this is the static constructor
        Registry.add "type1" .... 
    }
}

In .NET static constructors are not eagerly initialized1. This means, if you want to cause the .NET runtime to call the Handler1 static constructor, you need to access a static member of the type Handler1.

An example of using the type in a static context would be to

  1. Expose a sufficiently accessible static member/method:

    module Handler1 =
        [<Literal>]
        let Name = "Handler1"
    
  2. Access that static member from your code, such as the main method:

    [<EntryPoint>]
    let main args =
        printf Handler1.Name 
    

The above line will force the .NET runtime to load the Handler1 type's static context, which will result in invoking the static constructor if the type is encoutered by your code for the first time. If your code never encounters a given type's static context (any static member or method), then it will never be initialized -- the static constructors will never get called.

This behaviour is by design of the .NET framework (and that is regardless of the chosen language -- C#, F#, VB, others -- they all compile to similar IL). The point is to not allocate unnecessary resources by types that are never actually used.


1 Until .NET 4, static type context was initialized when the given type was first encountered by the executing code, regardless if the user code is interacting with instace or static members of that type. After .NET 4, this slightly changed -- the static context is initialized only when the user code interacts with static members of the type.

Upvotes: 3

Related Questions