How do I create a Union type in F # that is a value type?
Normal F # Discriminatory unions are reference types. How can I create a simple (non-recursive and only value type fields) union type in F # that is a value type?
Based on an internet search, my current (non-working) attempt looks like this:
[<StructLayout(LayoutKind.Explicit)>]
type Float =
[<DefaultValue>] [<FieldOffset 0>] val mutable Val1 : float
[<DefaultValue>] [<FieldOffset 0>] val mutable Int1 : int
new (a:float) = {Val1 = a}
The following blog post will appear to show what is possible with C #
I know this is NOT an IDIOMATIC use of F #, but I am trying to optimize the performance of a portion of my application and profiling has clearly shown that the cost of heap allocation (JIT_new) is what is causing my performance bottleneck ... A simple join type is ideal data structure for my needs, not a heap allocated.
source to share
First of all, I probably wouldn't have done this unless I had very good reason. Most of the time, the difference between structs and reference types isn't really that big - in my experience, it only matters when you have a very large array of them (then structs allow one large chunk of memory to be allocated).
However, it looks like F # doesn't like the constructor code in your example. I really don't know why (seems to do some checking that doesn't quite work for overlapping structures), but the following does the trick:
[<Struct; StructLayout(LayoutKind.Explicit)>]
type MyStruct =
[<DefaultValue; FieldOffset 0>]
val mutable Val1 : float
[<DefaultValue; FieldOffset 0>]
val mutable Int1 : int
static member Int(a:int) = MyStruct(Int1=a)
static member Float(f:float) = MyStruct(Val1=f)
If I really wanted to use that, I would add another field Tag
containing 1
or 0
, whichever case your struct represents. Then you can match the pattern to it using the active pattern and return some discriminated join security:
let (|Float|Int|) (s:MyStruct) =
if s.Tag = 0 then Float(s.Val1) else Int(s.Int1)
source to share