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.


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.