I have faced with an interesting F# behaviour on the null check. I tried to make a MongoDB query using C# Driver LINQ but F# compiler said that I could not compare the result with null, because result could not be null, but I am sure that query can return nothing =).
I am going to show you the same behaviour with classic LINQ. Please, look at the source code:
open System
open System.Linq
open System.Collections.Generic
type typeA = {Variable:int}
let x = List<typeA>().FirstOrDefault()
if (x = null) then None else Some(x)
If you evaluate first 7 lines of code, you will see that x is equal to null, List is empty, so the value of our LINQ query will be default(null). But, if you try to execute the line number 9, F# compiler will say that it cannot be compiled, because the typeA does not have a null as a proper value, but x is null! Hmm… real magic…
null_trick.fsx(9,9): error FS0043: The type ‘typeA’ does not have ‘null’ as a proper value
Actually, there is an excellent MSDN article “Null Values (F#)“, which should be read carefully. At the first look you may think that AllowNullLiteralAttribute is an answer and try to modify the typeA in the following way:
[<AllowNullLiteral>]
type typeA = {Variable:int}
But you can not have this code compiled, because
null_trick.fsx(6,6): error FS0934: Records, union, abbreviations and struct types cannot have the ‘AllowNullLiteral’ attribute
CLIMutableAttrubute is not an option too, because it does not affect null-behaviour. At the end of the “Null Values (F#)” article you will see an interesting example with a null check:
match box value with
| null -> printf "The value is null."
| _ -> printf "The value is not null."
Boxing is an answer! We need it to perform a null check for an arbitrary value. So, the working example will look like:
open System
open System.Linq
open System.Collections.Generic
type typeA = {Variable:int}
let x = List<typeA>().FirstOrDefault()
if (box x = null) then None else Some(x)
F# world is full of magic. Wonders await us at every turn.
P.S. Read more tales of null in Steffen Forkmann’s blog.