2

In a Visual Studio project for an F# library I have defined a function as

let inline Estimate (s : ^a seq) (f : float) (w : int) : float * float = ..

The type of Estimate is

val Estimate : s:seq<'a> -> f:float -> w:int -> float*float

Calling Estimate from a script within that project works as expected.

Now if I compile the project with the --standalone switch and reference the output DLL from another project, Estimate is shown to be

Estimate<'a,'a>(s: Collections.Generic.IEnumerabls<'a>, f: float, w:int) : float*float

i.e. it some reason now takes tuple arguments. Thus the following does not work

let q, p = EstimationQuality.Estimate x f 1 // This value is not a function and cannot be applied

but calling it with tuple parameters works fine

let q, p = EstimationQuality.Estimate (x, f, 1) // No problem.

What's wrong here? Is it a bug in the compiler?

EDIT:
Digging a little deeper, it appears that the problem is linked with the use of LanguagePrimitives.GenericZero.

While the problem actually compiles with the tuple parameter call, i get a runtime error when Estimate is called.

An unhandled exception of type 'System.TypeInitializationException' occurred in LibraryTest.dll

Additional information: The type initializer for 'GenericZeroDynamicImplTable`1' threw an exception.

kasperhj
  • 10,052
  • 21
  • 63
  • 106

1 Answers1

3

Compiling an F# DLL which is intended to be used from F#, with the standalone switch is not a good idea.

Why? Because all the F# metadata is lost since the whole set of F# types are included in your DLL so those types get a different identity from the types of the F# application that call your DLL or fsi.

The caller assembly uses the types in Fsharp.Core.dll which now are not the same as the ones used in your standalone compiled DLL.

That's why you see the tupled arguments, as seen from C# which doesn't understand F# metadata at all.

Generic inline functions using static constraints break as well since they need the metadata to inline at the call site.

Compiling also the caller assembly as standalone would make things worse, then you will have 3 sets of Fsharp types with different identities.

I think the standalone switch is fine when used only in the 'end-user' application.

Gus
  • 25,839
  • 2
  • 51
  • 76
  • This make sense. Thanks. I am investigating whether my problem is solely related to `--standalone` switch (see my edit). I think I have now produced the exception without the use of `--standalone`. This belongs in a question of its own. – kasperhj Jan 23 '15 at 14:57