I am trying to explain the strange behavior of the F # compiler between Release and Debug configurations regarding transitive dependencies. I will use the Newtonsoft.Json package as a base dependency here, because the further I managed to identify the problem, the smaller this example.
Create a library project called SerializerProject , referencing Newtonsoft.Json via paket. There is only one module in this project:
module Serializer = open System.IO open System.Text open Newtonsoft.Json type OptionConverter() = inherit JsonConverter() (* only the signature is important, the implementation and other methods are not interesting *) override x.WriteJson(writer: JsonWriter, value: obj, serializer: JsonSerializer) = (* ... *) let fromJson<'a> (bytes: byte []): 'a = let s = Encoding.UTF8.GetString(bytes) use sr = new StringReader(s) use jr = new JsonTextReader(sr) let serializer = JsonSerializer() serializer.Converters.Add(OptionConverter()) serializer.Deserialize<'a>(jr)
Now let me create a second project in the same solution and link SerializerProject via the link to the project. I would like to use fromJson in my new project, so I primarily referred to SerializerProject .
module MyModule = open Serializer (* This is here just so we reference the fromJson function *) let deserializer bytes = fromJson bytes
This is a minimal example for reproducing behavior.
Now, when I create the solution in the Debug configuration, everything compiles and works fine. But when I switch to Release, compilation fails in the second project, in MyModule in the deserializer definition. The exact error message is:
The type referenced by "Newtonsoft.Json.JsonWriter" is defined in an assembly that is not referenced. You must add a link to the assembly "Newtonsoft.Json"
I am using Visual Studio 2015 Update 3, F # tools (fsc, fsi) show version 14.0.23413.0.
This makes sense because it reads the SerializerProject metadata and discovers that the public OptionConverter type OptionConverter losing the JsonWriter type in the public WriteJson method (as well as other types and other methods, but it comes across first), but what makes me wonder why this works in debug mode and is only a problem in release mode.
- What additional steps does the compiler do for this?
- Why is this not a problem in the Debug assembly when the type defined in
Newtonsoft.Json really flows transitively into the second project?
As suggested in the comments, I tried to reference Newtonsoft.Json and decompile the second assembly using ILSpy to see if embedding would be enabled by compiler optimizations here, but even in the Release configuration, the second assembly looks like this:
call !!0 [SerializerProject]Serializer::fromJson<!a>(uint8[])
The fromJson function fromJson not built-in to directly display the JsonWriter type, so it seems something more subtle is happening.
This is not a lock problem, I just made the types of converters closed, since I do not want to use them from the outside, but I would like to delve into the internal workings of the F # compiler.