I need to interop with some C# code with F#. Null is a possible value that it is given so I need to check if the value was null. The docs suggest using pattern matching as such:
match value with | null -> ... | _ -> ...
The problem I'm having is the original code is structured in C# as:
if ( value != null ) { ... }
How do I do the equivalent in F#? Is there a no-op for pattern matching? Is there a way to check for null with an if statement?
Putting the median or mean of the whole column was the simple approach. But I like a bit more specific approach to the median and mean. Instead of taking the median of the whole age column and filling up all the null values, filling up the null values using the mean age of each pclass and 'alive' will be more accurate.
The null value is not normally used in F# for values or variables. However, null appears as an abnormal value in certain situations. If a type is defined in F#, null is not permitted as a regular value unless the AllowNullLiteral attribute is applied to the type.
Javascript null is a primitive type that has one value null. JavaScript uses the null value to represent a missing object. Use the strict equality operator ( === ) to check if a value is null . The typeof null returns 'object' , which is historical bug in JavaScript that may never be fixed.
For some reason (I haven't yet investigated why) not (obj.ReferenceEquals(value, null))
performs much better than value <> null
. I write a lot of F# code that is used from C#, so I keep an "interop" module around to ease dealing with null
. Also, if you'd rather have your "normal" case first when pattern matching, you can use an active pattern:
let (|NotNull|_|) value = if obj.ReferenceEquals(value, null) then None else Some() match value with | NotNull -> //do something with value | _ -> nullArg "value"
If you want a simple if
statement, this works too:
let inline notNull value = not (obj.ReferenceEquals(value, null)) if notNull value then //do something with value
Here are some benchmarks and additional information on the performance discrepancy:
let inline isNull value = (value = null) let inline isNullFast value = obj.ReferenceEquals(value, null) let items = List.init 10000000 (fun _ -> null:obj) let test f = items |> Seq.forall f |> printfn "%b" #time "on" test isNull //Real: 00:00:01.512, CPU: 00:00:01.513, GC gen0: 0, gen1: 0, gen2: 0 test isNullFast //Real: 00:00:00.195, CPU: 00:00:00.202, GC gen0: 0, gen1: 0, gen2: 0
A speed-up of 775% -- not too bad. After looking at the code in .NET Reflector: ReferenceEquals
is a native/unmanaged function. The =
operator calls HashCompare.GenericEqualityIntrinsic<'T>
, ultimately ending up at the internal function GenericEqualityObj
. In Reflector, this beauty decompiles to 122 lines of C#. Obviously, equality is a complicated issue. For null
-checking a simple reference comparison is enough, so you can avoid the cost of subtler equality semantics.
Pattern matching also avoids the overhead of the equality operator. The following function performs similarly to ReferenceEquals
, but only works with types defined outside F# or decorated with [<AllowNullLiteral>]
.
let inline isNullMatch value = match value with null -> true | _ -> false test isNullMatch //Real: 00:00:00.205, CPU: 00:00:00.202, GC gen0: 0, gen1: 0, gen2: 0
As noted in Maslow's comment, an isNull
operator was added in F# 4.0. It's defined the same as isNullMatch
above, and therefore performs optimally.
If you don't want to do anything in the null case, then you can use the unit value ()
:
match value with | null -> () | _ -> // your code here
Of course, you could also do the null check just like in C#, which is probably clearer in this case:
if value <> null then // your code here
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With