I posted a question to StackOverflow yesterday and will describe the issue and resolution in this post.
F# is a funny language in that it is a functional (I suppose it's multi-paradigm but very strong emphasis on functional) language built on the .NET platform which has a very different style as a whole. I had an interesting issue the other day where I noticed a null
value at runtime being returned from a .NET component in a place that F# was certain null
values could not exist.
In my case this was Entity Framework. I followed this walkthrough to create F# types that mapped to my database using Entity Framework Code First. I wrote a query that ended in .FirstOrDefault() and here is where the problem started:
let result = context
.SearchResults
.Where((fun (r:SearchResult) -> r.Program = request.Program))
.OrderByDescending((fun r -> r.AcquisitionDate))
.FirstOrDefault()
Now .FirstOrDefault()
is implemented such that it returns either the first element if one exists, or default(T)
if not. Well my SearchResult
type is defined in F# and is just a regular class so the default(typeof(SearchResult))
is equal to null
. However, F# doesn't allow nulls be default - due to its functional nature it doesn't by default support null
values (which I've come to really appreciate when I'm writing 'pure' F#). So when the database has no data, what value do you think is bound to result
?
If you guessed null
you were right. But I just said that F# doesn't support null
. So the following code does not compile:
match result with
| null -> () // do nothing since this doesn't compile anyway
| price -> () // do nothing since this doesn't compile anyway
the compilation error states
the type 'SearchResult' does not have 'null' as a proper value
Interesting. So SearchResult doesn't support null
. Even more interesting is if you comment out the bad code and run it you'll see that result
which is of type SearchResult
is indeed bound to null
.
It seems to me that in a world of uncertainty – a world of mixed paradigms - F# assumes a convention. F# assumes that every component is as functionally pure as it is - though it is made to interoperate with components that are known not to be.
It turns out that the fix to this is pretty simple. As stated in the first paragraph in the MSDN article on nulls in F#, F# has an AllowNullLiteral
attribute. I decorated my EF types with this and then the compiler allowed me to compare my results
value to null
. How imperative!