assembly.jc
assembly.jc

Reputation: 2066

Why None change to null automatically in F#

When try the following code in F# interactive

> let a = None
- let b = (a, Some 1);;    
> b;;
val it : 'a option * int option = (null, Some 1)

It show that b has type 'a option * int option, the type of b is correct. However, the value of first element of the tuple is null, not None, Why?

When try to verify the first element of the tuple whether really is null

printfn "%s" (match b with (null, _) -> "null" | _ -> "not null");;

it gives the following error

error FS0043: The type ''a option' does not have 'null' as a prope r value

When try to get the fisrt value in tuple,

let c = fst b;;

it gives

error FS0030: Value restriction. The value 'c' has been inferred to have generic type val c : '_a option Either define 'c' as a simple data term, make it a function with explicit argume nts or, if you do not intend for it to be generic, add a type annotation.

Upvotes: 1

Views: 836

Answers (1)

AMieres
AMieres

Reputation: 5004

The internal representation for the value None is indeed a null value. But that is the internal representation, the compiler identifies null and None as two completely different values, so you cannot compare them as they are different types. That is why you get: error FS0043.

This is actually something to be careful of:

let a = None
let b = (a, Some 1) 

let print  v = printfn "%A" v

sprintf "%A" a     |> print   // "<null>"
sprintf "%A" b     |> print   // "(None, Some 1)"
sprintf "%O" a     |> print   // "<null>"
sprintf "%O" b     |> print   // "(, Some(1))"
string       a     |> print   // ""
string       b     |> print   // "(, Some(1))"
a      .IsNone     |> print   // true
a      .IsSome     |> print   // false
a      .GetType()  |> print   // System.NullReferenceException: Object reference not set to an instance of an object.
a      .ToString() |> print   // System.NullReferenceException: Object reference not set to an instance of an object.
(fst b).ToString() |> print   // System.NullReferenceException: Object reference not set to an instance of an object.
(snd b).ToString() |> print   // "Some(1)"

... because calling some methods on a None value throws the dreaded NullReference Exception and converting to string is also erratic.

Regarding error FS0030 basically values cannot be generic. This has been discussed many times in SO.

Values from Discriminated Unions seem to be treated in a special way, they seem to be granted an exception, for instance these are generic and still Ok:

type MyDU<'A, 'B> =
| ValNo
| ValA of 'A
| ValB of 'B

let v1 = ValNo   // MyDU<'a,'b> double generic but Ok
let v2 = ValA 1  // MyDU<int,'a> generic but Ok
let v3 = ValB 1  // MyDU<'a,int> generic but Ok

but these are not Ok

let valNo() = ValNo
let valA  a = ValA a
let valB  b = ValB b

let w1 = valNo()   // MyDU<'_a,'_b> double generic not Ok
let w2 = valA 1  // MyDU<int,'_a> generic not Ok
let w3 = valB 1  // MyDU<'_a,int> generic not Ok

Upvotes: 6

Related Questions