Without question, this should be a struct. It's immutable and 16 bytes. Looking at the disassembly, this reference type:
type InputParam =
| RegionString of string
| RegionFloat of float32
And this reference type:
type InputParam =
| RegionString of RegionString: string
| RegionFloat of RegionFloat: float32
Are functionally identical. The only difference is with how the compiler named things. They both create a subclass called "RegionString" but with different property names -- "RegionString.item" vs "RegionString.RegionString".
When you convert the first example into a struct, it does away with the subclasses and tries to stick 2 "item" properties on the record which causes the FS3204 unique name error.
As far as performance, you should use structs on every tiny type like these when composing. Consider this example script:
type Name = Name of string
let ReverseName (Name s) =
s.ToCharArray() |> Array.rev |> System.String |> Name
[<Struct>]
type StrName = StrName of string
let StrReverseName (StrName s) =
s.ToCharArray() |> Array.rev |> System.String |> StrName
#time
Array.init 10000000 (fun x -> Name (x.ToString()))
|> Array.map ReverseName
|> ignore
#time
#time
Array.init 10000000 (fun x -> StrName (x.ToString()))
|> Array.map StrReverseName
|> ignore
#time
sizeof<Name>
sizeof<StrName>
The first one wraps a ref type in a ref type which doubled the performance hit:
Real: 00:00:04.637, CPU: 00:00:04.703, GC gen0: 340, gen1: 104, gen2: 7
...
Real: 00:00:02.620, CPU: 00:00:02.625, GC gen0: 257, gen1: 73, gen2: 1
...
val it : int = 8
val it : int = 8
Functional domain modeling is awesome, but you have to keep in mind that these have the same performance overhead:
let c = CustomerID 5
let i = 5 :> obj
The recommendation is anything immutable under 16 bytes should be a struct. If it was over 16 bytes, you had to look at the behavior. If it's being passed around a lot, you might be better off passing the 64-bit ref pointer and taking the ref overhead hit. But for internal data when composing types or within a function, stick with structs.