F# uses structural equality for the =
operator, which is almost always what you want:
let a = [1; 2; 3] let b = [1; 2; 3] printfn "%A" (a = b) // Prints "true"
But in some algorithms, it can be important to be able to ask "Are these two things the same object?" This can help with detecting cycles in a graph, for example. So how do I ask for reference equality in F#? I.e., how do I write the isSameObject
function below?
let isSameObject x y = ??? 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"
Use the ReferenceEquals method to determine whether two references refer to the same object. The concept of reference equality applies only to reference types. Value type objects cannot have reference equality because when an instance of a value type is assigned to a variable, a copy of the value is made.
== operator is used to check whether two variables reference objects with the same value.
The only this you need is "==" equality operator.
f1 is f2 checks if two references are to the same object. Under the hood, this compares the results of id(f1) == id(f2) using the id builtin function, which returns a integer that's guaranteed unique to the object (but only within the object's lifetime).
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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With