As I mentioned in the previous post, F# types (as opposed to classes) cannot be null
. That is, you cannot explicitly make them null, but you can still end up with a null
value. Here’s how:
1 type Foo =
2 { x : int }
3
4 let varObj : Object = null
5 let varFoo1 : Foo = null // this won't work
6 let varFoo2 : Foo = varObj :?> Foo // this will
Line 5 will simply not compile, stating that null
is not a valid value for type Foo
. Line 6 will compile. I expected to get a runtime exception when executing line 6, but it did not happen. The exception occurs only when we try to access varFoo2.x
. E.g. I can pass varFoo2
to a function without error. So, effectively varFoo2
works as a null
value of type Foo
, which we were told cannot exist.
So, if downcasts are involved, even record types can be nullable. This may be a nasty surprise for the developer, especially since there is no protection against this. There is no way to check whether a variable of type Foo
is null
: the compiler will tell you that it can never be null
🙂
Ending up with null
values for record types is not completely unexpected, since F# record types are internally represented by .NET classes, which are nullable. To avoid nulls, F# compiler needs to closely guard all possible ways by which a variable of a record type may end up with a null
value. This is one possible path they did not catch.
Permalink
This isn’t valid anymore, you’ll get a runtime error during casting it (null reference exception)!