Reputation: 837
I have a record type like this:
type Node<'T> = { doStuff: 'T -> unit ; id: int }
How can I implement equality/comparible so that only the id is equated/compared?
Note: This needs to work between nodes of different types. So equate/compare a Node<int>
and a Node<string>
. It doesn't seem trivial when generics are involved.
Upvotes: 2
Views: 576
Reputation: 6223
It could be done via a common base type:
type IHaveId =
abstract Id : int
inherit System.IComparable
type [<CustomEquality; CustomComparison>] Node<'T> =
{ DoStuff: 'T -> unit ; Id: int }
interface IHaveId with
member n.Id = n.Id
override n.Equals n' =
match n' with
| :? IHaveId as n' -> n.Id = n'.Id
| _ -> invalidArg "n'" "Tried to equate incompatible types."
override n.GetHashCode () = n.Id.GetHashCode()
interface System.IComparable with
member n.CompareTo n' =
match n' with
| :? IHaveId as n' -> n.Id.CompareTo n'.Id
| _ -> invalidArg "n'" "Tried to compare incompatible types."
Note that this isn't very fast. Also, be careful: With public construction access to Node<'T>
, it would be possible to construct nodes that do something different but are treated as equals.
Using an interface for DoStuff
would allow structural comparison. If the objects and their IDs are centrally constructed, I'd consider [<ReferenceEquality>]
and explicitly passing a comparison function to collections that require it (such as Set<_>
or Map<_>
).
Upvotes: 2
Reputation: 2395
I would guess that writing a static member for that type will be some solution
static member compareNodes (n1:Node<_>) (n2:Node<_>) =
n1.id.CompareTo(n2.id)
Upvotes: 1