Search code examples
f#privatecilinternalsvisibleto

If private entities in F# compile to internal, why doesn't InternalsVisibleTo work?


From the F# 4.0 spec [PDF]:

The CLI compiled form of all non-public entities is internal.

In my main project I have a function defined as

namespace MyNamespace.Foo
module Bar =
  module Baz =
    let private myFun ...

In the main project's ``AssemblyInfo.fs` I have

[<assembly: InternalsVisibleTo("MyNamespace.Tests")>]

(I've double-checked the name.)

However, in the test assembly (also F#), I get an error when referencing myFun saying The value 'myFun' is not accessible from this code location. Everything works fine if I remove private from the definition of myFun.

Strangely enough I am also able to call the private myFun from a C# project even without InternalsVisibleTo.

Why is the private myFun not accessible from the test assembly when private entities compile to internal and I've specified InternalsVisibleTo on the main assembly?


Solution

  • I think there is a difference between the language level and the compiled code level.

    • At language level, private behaves as private, so you are only allowed to call the function within the module. If you mark the binding as internal, it will behave as internal and you'll be able to call it from the same assembly.

    • At compiled code level, private s compiled as internal, presumably so that you can use things like closures and sequence expressions, but the F# compiler knows that this is just a compilation artifact.

    I have not tried this, but I'd guess that if you referenced the assembly from C# then it would behave as internal because the C# compiler does not understand the special metadata that the F# compiler puts in to mark the let binding.