Symptom: A weird error such as:
error FS0001: This expression was expected to have type
'FSI_0011.MyType'
but here has type
'FSI_0012.MyType'
How can they be different types when you know for sure that MyType
is only defined once!
Say that you have a file called ModuleA.fsx
type A = {a:int}
And then you #load it into a file called ModuleB.fsx
#load "ModuleA.fsx"
// alias for type A
type B = ModuleA.A
// instance of type A
let b :ModuleA.A = {a=1}
And do the same in ModuleC.fsx
#load "ModuleA.fsx"
// alias for type A
type C = ModuleA.A
// instance of type A
let c :ModuleA.A = {a=1}
Finally, you reference both B and C in ModuleD.fsx
. Now you get errors!
#load "ModuleB.fsx"
#load "ModuleC.fsx"
// compare the instances in the modules
ModuleB.b = ModuleC.c // ERROR
(*
ModuleD.fsx(12,13): error FS0001: This expression was expected to have type
'FSI_0011.ModuleA.A'
but here has type
'FSI_0012.ModuleA.A'
*)
// create two values via the type aliases
let b : ModuleB.B = {a=1}
let c : ModuleC.C = {a=1}
b = c // ERROR
(*
ModuleD.fsx(16,5): error FS0001: This expression was expected to have type
'ModuleB.B'
but here has type
'ModuleC.C'
*)
- ModuleA contains the domain types
- ModuleB contains the implementation of the core business logic (referencing the domain)
- ModuleC contains the DTO to Domain conversion logic (referencing the domain but not the core business logic)
- ModuleD is the top level API/Shell/Program script which references all three of the above.
In the top level program (ModuleD), it would be common to have a pipeline like this:
json
|> Dto.jsonToDto // implemented in ModuleC (DTO)
|> Dto.toDomain // implemented in ModuleC (DTO), but now referencing a domain type defined in ModuleA (Domain)
|> MyWorkflow.execute // implemented in ModuleB (implementation), referencing the SAME domain type in ModuleA (Domain)
And the pipeline now won't compile because of the incompatible types.
In moduleD, load both B and C in a single #load, not two separate ones. Like this:
#load "ModuleB.fsx" "ModuleC.fsx"
or
#load "ModuleB.fsx"
"ModuleC.fsx"
And now all the errors go away! Here's the updated ModuleD.fsx
:
#load "ModuleB.fsx" "ModuleC.fsx"
// compare the instances in the modules
ModuleB.b = ModuleC.c // NO ERROR
// create two values via the type aliases
let b : ModuleB.B = {a=1}
let c : ModuleC.C = {a=1}
b = c // NO ERROR