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.

+3


source to share


1 answer


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)

      

+9


source







All Articles