How do I check for reference equality in F#?

The answer, it turns out, is to use LanguagePrimitives.PhysicalEquality:

let isSameObject = LanguagePrimitives.PhysicalEquality
let a = [1; 2; 3]
let b = [1; 2; 3]
let a' = a
printfn "%A" (isSameObject a b)  // Prints "false"
printfn "%A" (isSameObject a a')  // Prints "true"

There was precisely one question I could find on Stack Overflow that asked about this:
short-cutting equality checking in F#? And since that question’s subject almost made me glance right past it, I figured I would ask (and answer) the question again. Hopefully this question’s subject line will make it easier to find when Googling for terms like “referential equality in F#”.

What about obj.ReferenceEquals?

In a comment, Fyodor Soikin asks what’s wrong with obj.ReferenceEquals. The answer is “not much”, but there are two ways in which LanguagePrimitives.PhysicalEquality is better than obj.ReferenceEquals for most F# code:

1) PhysicalEquality throws a compiler error when you pass it two different types, while obj.ReferenceEquals just takes two objs and therefore happily tries to compare an int list to char list:

let a = [1;2;3]
let b = ['a';'b';'c']

obj.ReferenceEquals(a,b) // Returns false
LanguagePrimitives.PhysicalEquality a b // Compiler error

2) PhysicalEquality won’t let you compare value types, only reference types. obj.ReferenceEquals will let you compare two value types, and will implicitly box them first. But it boxes each one separately, meaning that it will always return false even when you gave it the “same” value object:

let n = 3
let n' = n
obj.ReferenceEquals(n,n') // Returns false!
LanguagePrimitives.PhysicalEquality n n' // Compiler error

And, of course, there’s one other difference, which boils down to personal preference and ease-of-use. PhysicalEquality takes curried-style parameters, which plays nicely with type inference and partial application. obj.ReferenceEquals takes tupled-style parameters, which means it’s slightly uglier to use.

For all these reasons, LanguagePrimitives.PhysicalEquality is better to use, in almost every scenario, than obj.ReferenceEquals.

Leave a Comment

tech