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