Search code examples
f#nulloption-typebenchmarking

Option type benchmark using F#


I need to use Some/None options in heavy numerical simulations. The following micro benchmark gives me Fast = 485 and Slow = 5890.

I do not like nulls and even if I liked them I cannot use null because The type 'float' does not have 'null' as a proper value.

Ideally there would be a compiler option that would compile Some/None into value/null so there would be no runtime penalty. Is that possible? Or how shall I make Some/None efficient?

let s = System.Diagnostics.Stopwatch()

s.Start()
for h in 0 .. 1000 do
  Array.init 100000 (fun i -> (float i + 1.)) |> ignore
printfn "Fast = %d" s.ElapsedMilliseconds

s.Restart()
for h in 0 .. 1000 do
  Array.init 100000 (fun i -> Some (float i + 1.)) |> ignore
printfn "Slow = %d" s.ElapsedMilliseconds

Solution

  • None is actually already represented as null. But since option<_> is a reference type (which is necessary for null to be a valid value in the .NET type system), creating Some instances will necessarily require heap allocations. One alternative is to use the .NET System.Nullable<_> type, which is similar to option<_>, except that:

    1. it's a value type, so no heap allocation is needed
    2. it only supports value types as elements, so you can create an option<string>, but not a Nullable<string>. For your use case this seems like an unimportant factor.
    3. it has runtime support so that boxing a nullable without a value results in a null reference, which would be impossible otherwise

    Keep in mind that your benchmark does very little work, so the results are probably not typical of what you'd see with your real workload. Try to use a more meaningful benchmark based on your actual scenario if at all possible.

    As a side note, you get more meaningful diagnostics (including garbage collection statistics) if you use the #time directive in F# rather than bothering with the Stopwatch.