Monday, May 17, 2010

An interesting bit of F# behaviour

In one assembly, define a public static class in C#:

In another do something similar in F#:

which Reflector tells us is equivalent to

inside namespace ClassLibrary1. Now create another F# library referencing the previous two containing

The first line compiles; the second doesn't, failing with compile error error FS0039: The type 'Module1' is not defined.

Clearly the CompilationMapping is being sniffed by the typeof operation, because that is the only difference between the two.

4 comments :

Brian said...

It's not CompilationMapping, rather it's because typeof<AModule> is not allowed in F#. There's no good technical reason really, and we have a bug logged to remedy this, but it's a low priority since it's uncommon to want this for any real scenario.

Steve Gilham said...

The question is how it detected, in the separate assembly, that the code was an F# module rather than a C# static class -- and at the IL level the CompilationMapping attribute is the most blatant difference that can be what says "this static class is an F# module".

The use case is a simple piece of reflection -- wanting from one assembly to get the MethodInfo for one of the functions in the module, the sort of thing that in C# would just be typeof(Module1).GetMethod("Hello")

Brian said...

F# assemblies contain their own metadata (stored as a resource, see e.g. FSharp.PowerPack.Metadata), and it is the 'extra F# metadata' that identifies a static class as an F# module.

Steve Gilham said...

Thatks for the detail -- I stand corrected on the precise detection mechanism.

The point however remains that tyepof<'T> is examining F# fingerprints (not just the particulargaudy red herring I first spotted) and filtering accordingly. This isn't the obvious behaviour cross-assembly (where the source language isn't an obvious part of the public interface), so it's still worth flagging.