Search code examples
f#comparisonequality

Why are there two different syntaxes for CustomEquality and CustomComparison in F#?


I want to implement a type Symbol in F#, which has an associated string and position (let's say a line number in text). I would do as follows:

type Symbol = Symbol of string * int // (string, line number)

I want a custom equality that dismisses the line number. I will have a "strict equality" that takes the line number into account, but I want the default equality to compare only the strings. Looking at this SO post, it seems one has to do as follows:

[<CustomEquality; CustomComparison>]
type Symbol =
    | Symbol of string * int
    member x.GetString() =
        match x with
        | Symbol (s, _) -> s
    override x.Equals(y) = // Equality only compares strings, not positions.
        match y with
        | :? Symbol as i -> i.GetString() = x.GetString()
        | _ -> false
     override x.GetHashCode() =
        match x with
        | Symbol (s, p) -> hash (s, p)

However, to implement custom comparison, one has to add below the above declaration

    interface System.IComparable with
        member x.CompareTo(yobj) = 
            match yobj with
            | :? Symbol as y -> compare (x.GetString()) (y.GetString())
            | _ -> invalidArg "yobj" "cannot compare values of different types"

Why can I write override x.Equals(y)..., but not override x.CompareTo(yobj)...? Why do I have to specify interface System.IComparable with ...? It seems there exists a System.IEquatable, but I do not need to specify it, why? It is not a big difference, but I was just wondering why the difference was here.


Solution

  • The difference is that for Equals you're overriding Object.Equals - which is a virtual method on a base class, while for CompareTo you're implementing an interface (which in F# requires explicit implementation via "interface .. with".