Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I check for reference equality in F#?

Tags:

equality

f#

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" 
like image 227
rmunn Avatar asked Aug 30 '16 00:08

rmunn


People also ask

Which is used to check the reference equality?

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.

Does == check for reference?

== operator is used to check whether two variables reference objects with the same value.

Is this the best way to check for object reference equality?

The only this you need is "==" equality operator.

What is reference equality in Python?

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).


1 Answers

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.

like image 174
rmunn Avatar answered Oct 04 '22 09:10

rmunn