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 obj
s 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
.