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?
If you don't want to do anything in the null case, then you can use the unit value
()
:Of course, you could also do the null check just like in C#, which is probably clearer in this case:
I've recently faced a similar dilemma. My issue was that I exposed an F#-developed API that could be consumed from C# code. C# has no issue passing
null
to a method that accepts interfaces or classes, but if the method and the types of its arguments are F# types, you are not allowed to properly do the null checks.The reason is that F# types initially do not accept the
null
literal, while technically nothing in the CLR protects your API from being improperly invoked, especially from a more null-tolerant language such as C#. You would initially end up being unable to properly null-protect yourself unless you use the[<AllowNullLiteral>]
attribute, which is quite an ugly approach.So, I've come to this solution in the related topic, which allows me to keep my F# code clean and F#-friendly. In general I create a function that will accept any object and will convert it to an
Option
, then instead ofnull
I will validate againstNone
. This is similar to using the pre-defined in F#Option.ofObj
function, but the latter does require the object passed to be explicitly nullable (thus annotated with theAllowNullLiteral
uglyness).Of course nulls are generally discouraged in F#, but...
Without going into examples etc there's an article with some examples @ MSDN here. It reveals specifically how to detect a null -- and you can then parse it out of the input or handle as desired.
For some reason (I haven't yet investigated why)
not (obj.ReferenceEquals(value, null))
performs much better thanvalue <> null
. I write a lot of F# code that is used from C#, so I keep an "interop" module around to ease dealing withnull
. Also, if you'd rather have your "normal" case first when pattern matching, you can use an active pattern:If you want a simple
if
statement, this works too:UPDATE
Here are some benchmarks and additional information on the performance discrepancy:
A speed-up of 775% -- not too bad. After looking at the code in .NET Reflector:
ReferenceEquals
is a native/unmanaged function. The=
operator callsHashCompare.GenericEqualityIntrinsic<'T>
, ultimately ending up at the internal functionGenericEqualityObj
. In Reflector, this beauty decompiles to 122 lines of C#. Obviously, equality is a complicated issue. Fornull
-checking a simple reference comparison is enough, so you can avoid the cost of subtler equality semantics.UPDATE 2
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>]
.UPDATE 3
As noted in Maslow's comment, an
isNull
operator was added in F# 4.0. It's defined the same asisNullMatch
above, and therefore performs optimally.If you have a type that has been declared in C# or a .NET library in general (not in F#) then
null
is a proper value of that type and you can easily compare the value againstnull
as posted by kvb. For example, assume that C# caller gives you an instance ofRandom
:Things become more tricky if the C# caller gives you a type that was declared in F#. Types declared in F# do not have
null
as a value and F# compiler will not allow you to assign themnull
or to check them againstnull
. The problem is that C# doesn't do this check and a C# caller could still give younull
. For example:In that case, you need either boxing or
Unchecked.defaultOf<_>
: