Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Testing for null reference in F#

Tags:

f#

Given the following:

[<DataContract>]
type TweetUser = {
    [<field:DataMember(Name="followers_count")>] Followers:int
    [<field:DataMember(Name="screen_name")>] Name:string
    [<field:DataMember(Name="id_str")>] Id:int
    [<field:DataMember(Name="location")>] Location:string}

[<DataContract>]
type Tweet = {
    [<field:DataMember(Name="id_str")>] Id:string
    [<field:DataMember(Name="text")>] Text:string
    [<field:DataMember(Name="retweeted")>] IsRetweeted:bool
    [<field:DataMember(Name="created_at")>] DateStr:string
    [<field:DataMember(Name="user", IsRequired=false)>] User:TweetUser
    [<field:DataMember(Name="sender", IsRequired=false)>] Sender:TweetUser
    [<field:DataMember(Name="source")>] Source:string}

Deserializing with DataContractJsonSerializer(typeof<Tweet[]>) will result in either the User or Sender field being null (at least that's what the debugger is telling me).

If I try to write the following:

    let name = if tweet.User <> null 
                  then tweet.User.Name
                  else tweet.Sender.Name

the compiler emits the error: "The type 'TweetUser' does not have 'null' as a proper value"

How do I test null values in this case?

like image 774
Mike Ward Avatar asked May 24 '12 23:05

Mike Ward


1 Answers

To cyclically expand on @Tomas' answer ;-]

let name = if not <| obj.ReferenceEquals (tweet.User, null)
              then tweet.User.Name
              else tweet.Sender.Name

or

let inline isNull (x:^T when ^T : not struct) = obj.ReferenceEquals (x, null)

Unchecked.defaultof<_> is doing the right thing and producing nulls for your record types; the issue is that the default equality operator uses generic structural comparison, which expects you to always play by F#'s rules when using F# types. In any case, a null-check really only warrants referential comparison in the first place.

like image 167
ildjarn Avatar answered Nov 12 '22 03:11

ildjarn