tags:

views:

261

answers:

4

Why aren't option types like "int option" compatible with nullable types like "Nullable"?

I assume there is some semantic reason for the difference, but I can't figure what that is.

An option in F# is used when a value may or may not exist. An option has an underlying type and may either hold a value of that type or it may not have a value.

http://msdn.microsoft.com/en-us/library/dd233245%28VS.100%29.aspx

That sure sounds like the Nullable structure.

A: 

Key difference is that must test the option type to see if it has a value. See this question for a good description of its semantics: http://stackoverflow.com/questions/624116/how-does-the-option-type-work-in-f

Robert
So what? You could make that requirement at the languge syntax level and still use Nullable<int> at the runtime level.
Jonathan Allen
At the runtime level they are represented using nulls.
Robert
Unfortunately you are wrong. You don't need to check option types to see if they have a value, you can just call Option<T>.Value directly and hope you don't get an exception. There isn't even a compiler warning if you don't use pattern matching.
Jonathan Allen
@Jonathan: It is advisable to test the option type, and that's the way it's intended to be used. Direct access to the value is provided for convenience, but one should refrain from using it.
Joh
Providing a convenience method and then telling people not to use it doesn't match the "pit of success" philosophy of .NET API design.
Jonathan Allen
A: 

Again, this is from my limited understanding, but the problem probably lies in how each gets rendered in the IL. The "nullable" structure probably gets handled slightly different from the option type.

You will find that the interactions between various .Net languages really boils down to how the IL gets rendered. Mostof the time it works just fine but on occasion, it causes issues. (check out this). Just when you thought it was safe to trust the level of abstraction. :)

Craig
Ye gods, that viewer is horrible. Nice article though...
flatline
+3  A: 

The two have different semantics. Just to name one, Nullable is an idempotent data constructor that only works on value types, whereas option is a normal generic type. So you can't have a

Nullable<Nullable<int>>

but you can have an

option<option<int>>

Generally, though there are some overlapping scenarios, there are also things you can do with one but not the other.

Brian
That explains why you can't use Nullable<Nullable<int>> as the runtime representation of option<option<int>>. That doesn't explain why you can't special case option<int> to be compatiable with Nullable<int>.
Jonathan Allen
Such a special case doesn't seem desirable to me. Why would you want certain instances of option<'a> to be represented by Nullable<T> and not others?
Robert
F# is already full of strange special cases. For example, what is the difference between a "string" which takes a value or null and a "string option" which takes a value or a none?
Jonathan Allen
+1  A: 

Because of the runtime representation choice for System.Nullable<'T>.

Nullable tries to represent the absent of values by the null pointer, and present values by pointers to those values.

(new System.Nullable<int>() :> obj) = null
|> printfn "%b" // true

(new System.Nullable<int>(1) :> obj).GetType().Name
|> printfn "%s" // Int32

Now consider strings. Unfortunately, strings are nullable. So this is valid:

null : string

But now a null runtime value is ambiguous - it can refer to either the absence of a value or a presence of a null value. For this reason, .NET does not allow constructing a System.Nullable<string>.

Contrast this with:

(Some (null : string) :> obj).GetType().Name
|> printfn "%s" // Option`1

That being said, one can define a bijection:

let optionOfNullable (a : System.Nullable<'T>) = 
    if a.HasValue then
        Some a.Value
    else
        None

let nullableOfOption = function
    | None -> new System.Nullable<_>()
    | Some x -> new System.Nullable<_>(x)

If you observe the types, these functions constrain 'T to be a structure and have a zero-argument constructor. So perhaps F# compiler could expose .NET functions receiving/returning Nullable<'T> by substituting it for an Option<'T where 'T : struct and 'T : (new : unit -> 'T)>, and inserting the conversion functions where necessary..

toyvo