Is it legal for a record to have a nullable field such as:
type MyRec = { startDate : System.Nullable<DateTime>; }
This example does build in my project, but is this good practice if it is legal, and what problems if any does this introduce?
It is legal, but F# encourage using option types instead:
type MyRec = { startDate : option<DateTime>; }
By using option you can easily pattern match against options and other operations to transform option values as for example map values (by using Option.map), and abstractions such as the Maybe monad (by using Option.bind), whereas with nullable you can't since only value types can be made nullables.
You will notice most F# functions (such as List.choose) work with options instead of nullables. Some language features like optional parameters are interpreted as the F# option type.
However in some cases, when you need to interact with C# you may want to use Nullable.
When usign Linq to query a DB you may consider using the Linq.Nullable Module and the Nullable operators
F# does not allow types that are declared in F# to be null. However, if you're using types that are not defined in F#, you are still allowed to use null. This is why your code is still legal. This is needed for inter-operability, because you may need to pass null to a .NET library or accept it as a result.
But I would say it is not a good practice unless your need is specifically of inter-operability. As others pointed out, you can use the option feature. However, this doesn't create an optional record field whose value you don't need to specify when creating it. To create a value of the record type, you still need to provide the value of the optional field.
Also, you can mark a type with the AllowNullLiteral attribute, and F# compiler would allow null as a value for that specific type, even if it is a type declared in F#. But AllowNullLiteral can't be applied to record types.
Oh and I almost forgot to mention: option types are NOT compatible with nullable types. Something that I kind of naively expected to just work (stupid me!). See this nice SO discussion for details.
Related
Suppose one needs a numeric data type whose allowed values fall within a specified range. More concretely, suppose one wants to define an integral type whose min value is 0 and maximum value is 5000. This type of scenario arises in many situations, such as when modeling a database data type, an XSD data type and so on.
What is the best way to model such a type in F#? In C#, one way to do this would be to define a struct that implemented the range checking overloaded operators, formatting and so on. A analogous approach in F# is described here: http://tomasp.net/blog/fsharp-custom-numeric.aspx/
I don't really need though a fully-fledged custom type; all I really want is an existing type with a constrained domain. For example, I would like to be able to write something like
type MyInt = Value of uint16 where Value <= 5000 (pseudocode)
Is there a shorthand way to do such a thing in F# or is the best approach to implement a custom numeric type as described in the aforementioned blog post?
You're referring to what are called refinement types in type theory, and as pointed out by Daniel, look for F*. But it is a research project.
As far as doing it with F#, in addition to Tomas' post, take a look at the designing with types series.
My suggestion would be to implement a custom struct wrapping your data type (e.g., int), just as you would in C#.
The idea behind creating this custom struct is that it allows you to "intercept" all uses of the underlying data value at run-time and check them for correctness. The alternative is to check all of these uses at compile-time, which is possible with something like F* (as others mentioned), although it's much more difficult and not something you would use for everyday code.
Which way is more idiomatic to use Nullable<'a> or to use Option<'a> for representing a nullable int?
Option is far more idiomatic in F# code.
It has far nicer syntax when used in match and has large amounts of support from the standard library.
However, if you plan to access the code from C# or some other language you should probably expose the interface with Nullable which is easier to use in C#.
As John said, Option<T> is definitely more idiomatic type in F#. I would certainly use options as my default choice - the Option module provides many useful functions, pattern matching works nicely on options and F# libraries are generally designed to work with options.
That said, there are two cases when you might want to use nullable:
When creating arrays of optional values - Nullable<T> is a value type (sort of) and if you create an array Nullable<T>[] then it is allocated as continuous memory block. On the other hand options are reference types and option<T>[] will be an array of references to heap-allocated objects.
When you need to write some calculations and propagate missing values - in F# 3.0, there is a module Microsoft.FSharp.Linq.NullableOperators which implements various operators for dealing with nullable values (see MSDN documentation) which lets you write e.g.:
let one = Nullable(1)
let two = Nullable(2)
// Add constant to nullable, then compare value of two nullables
(one ?+ 2) ?>=? two
In F# mantra there seems to be a visceral avoidance of null, Nullable<T> and its ilk. In exchange, we are supposed to instead use option types. To be honest, I don't really see the difference.
My understanding of the F# option type is that it allows you to specify a type which can contain any of its normal values, or None. For example, an Option<int> allows all of the values that an int can have, in addition to None.
My understanding of the C# nullable types is that it allows you to specify a type which can contain any of its normal values, or null. For example, a Nullable<int> a.k.a int? allows all of the values that an int can have, in addition to null.
What's the difference? Do some vocabulary replacement with Nullable and Option, null and None, and you basically have the same thing. What's all the fuss over null about?
F# options are general, you can create Option<'T> for any type 'T.
Nullable<T> is a terrifically weird type; you can only apply it to structs, and though the Nullable type is itself a struct, it cannot be applied to itself. So you cannot create Nullable<Nullable<int>>, whereas you can create Option<Option<int>>. They had to do some framework magic to make that work for Nullable. In any case, this means that for Nullables, you have to know a priori if the type is a class or a struct, and if it's a class, you need to just use null rather than Nullable. It's an ugly leaky abstraction; it's main value seems to be with database interop, as I guess it's common to have `int, or no value' objects to deal with in database domains.
Im my opinion, the .Net framework is just an ugly mess when it comes to null and Nullable. You can argue either that F# 'adds to the mess' by having Option, or that it rescues you from the mess by suggesting that you avoid just null/Nullable (except when absolutely necessary for interop) and focus on clean solutions with Options. You can find people with both opinions.
You may also want to see
Best explanation for languages without null
Because every .NET reference type can have this extra, meaningless value—whether or not it ever is null, the possibility exists and you must check for it—and because Nullable uses null as its representation of "nothing," I think it makes a lot of sense to eliminate all that weirdness (which F# does) and require the possibility of "nothing" to be explicit. Option<_> does that.
What's the difference?
F# lets you choose whether or not you want your type to be an option type and, when you do, encourages you to check for None and makes the presence or absence of None explicit in the type.
C# forces every reference type to allow null and does not encourage you to check for null.
So it is merely a difference in defaults.
Do some vocabulary replacement with Nullable and Option, null and None, and you basically have the same thing. What's all the fuss over null about?
As languages like SML, OCaml and Haskell have shown, removing null removes a lot of run-time errors from real code. To the extent that the original creator of null even describes it as his "billion dollar mistake".
The advantage to using option is that it makes explicit that a variable can contain no value, whereas nullable types leave it implicit. Given a definition like:
string val = GetValue(object arg);
The type system does not document whether val can ever be null, or what will happen if arg is null. This means that repetitive checks need to be made at function boundaries to validate the assumptions of the caller and callee.
Along with pattern matching, code using option types can be statically checked to ensure both cases are handled, for example the following code results in a warning:
let f (io: int option) = function
| Some i -> i
As the OP mentions, there isn't much of a semantic difference between using the words optional or nullable when conveying optional types.
The problem with the built-in null system becomes apparent when you want to express non-optional types.
In C#, all reference types can be null. So, if we relied on the built-in null to express optional values, all reference types are forced to be optional ... whether the developer intended it or not. There is no way for a developer to specify a non-optional reference type (until C# 8).
So, the problem isn't with the semantic meaning of null. The problem is null is hijacked by reference types.
As a C# developer, i wish I could express optionality using the built-in null system. And that is exactly what C# 8 is doing with nullable reference types.
Well, one difference is that for a Nullable<T>, T can only be a struct which reduces the use cases dramatically.
Also make sure to read this answer: https://stackoverflow.com/a/947869/288703
I have a problem understanding co-existence of "null" and Option in F#. In a book I have read that null value is not a proper value in F# because this way F# eliminates the excessive null checking. But it still allows null-initialized references in F#. In other words, you can have null values but you don't have the weapons to defend yourself with. Why not completely replace nulls with Options. Is it because of compatibility issues with .NET libraries or languages that it's still there? If yes can you give an example that shows why it can't be replaced by Option?
F# avoids the use of null when possible, but it lives in the .NET eco-system, so it cannot avoid it completely. In a perfect world, there would be no null values, but you just sometimes need them.
For example, you may need to call .NET method with null as an argument and you may need to check whether a result of .NET method call was null.
The way F# deals with this is:
Null is used when working with types that come from .NET (When you have a value or argument of type declared in .NET, you can use null as a value of that type; you can test if it equals null)
Option is needed when working with F# types, because values of types declared in F# cannot be null (And compiler prohibits using null as a value of these types).
In F# programming, you'll probably use option when working with .NET types as well (if you have control over how their values are created). You'll just never create null value and then use option to have a guarantee that you'll always handle missing values correctly.
This is really the only option. If you wanted to view all types as options implicitly when accessing .NET API, pretty much every method would look like:
option<Control> GetNextChild(option<Form> form, option<Control> current);
...programming with API like this would be quite painful.
I am having a brain freeze on f#'s option types. I have 3 books and read all I can but I am not getting them.
Does someone have a clear and concise explanation and maybe a real world example?
TIA
Gary
Brian's answer has been rated as the best explanation of option types, so you should probably read it :-). I'll try to write a more concise explanation using a simple F# example...
Let's say you have a database of products and you want a function that searches the database and returns product with a specified name. What should the function do when there is no such product? When using null, the code could look like this:
Product p = GetProduct(name);
if (p != null)
Console.WriteLine(p.Description);
A problem with this approach is that you are not forced to perform the check, so you can easily write code that will throw an unexpected exception when product is not found:
Product p = GetProduct(name);
Console.WriteLine(p.Description);
When using option type, you're making the possibility of missing value explicit. Types defined in F# cannot have a null value and when you want to write a function that may or may not return value, you cannot return Product - instead you need to return option<Product>, so the above code would look like this (I added type annotations, so that you can see types):
let (p:option<Product>) = GetProduct(name)
match p with
| Some prod -> Console.WriteLine(prod.Description)
| None -> () // No product found
You cannot directly access the Description property, because the reuslt of the search is not Product. To get the actual Product value, you need to use pattern matching, which forces you to handle the case when a value is missing.
Summary. To summarize, the purpose of option type is to make the aspect of "missing value" explicit in the type and to force you to check whether a value is available each time you work with values that may possibly be missing.
See,
http://msdn.microsoft.com/en-us/library/dd233245.aspx
The intuition behind the option type is that it "implements" a null-value. But in contrast to null, you have to explicitly require that a value can be null, whereas in most other languages, references can be null by default. There is a similarity to SQLs NULL/NOT NULL if you are familiar with those.
Why is this clever? It is clever because the language can assume that no output of any expression can ever be null. Hence, it can eliminate all null-pointer checks from the code, yielding a lot of extra speed. Furthermore, it unties the programmer from having to check for the null-case all the same, should he or she want to produce safe code.
For the few cases where a program does require a null value, the option type exist. As an example, consider a function which asks for a key inside an .ini file. The key returned is an integer, but the .ini file might not contain the key. In this case, it does make sense to return 'null' if the key is not to be found. None of the integer values are useful - the user might have entered exactly this integer value in the file. Hence, we need to 'lift' the domain of integers and give it a new value representing "no information", i.e., the null. So we wrap the 'int' to an 'int option'. Now, if there is no integer value we will get 'None' and if there is an integer value, we will get 'Some(N)' where N is the integer value in question.
There are two beautiful consequences of the choice. One, we can use the general pattern match features of F# to discriminate the values in e.g., a case expression. Two, the framework of algebraic datatypes used to define the option type is exposed to the programmer. That is, if there were no option type in F# we could have created it ourselves!