I have a simple F# discriminated union that combines a bool, a string, and a float. I want to override the Object.Equals(arg) of this union so that I can put in an epsilon to account for precision errors when checking for float equality. The compiler complained that I if I override this.Equals(arg), I should also override this.GetHashCode() and this.CompareTo(arg). For these to overrides, I have no special functionality planned, so I'd simply like to call the default versions of these methods. In my implementation now, I have three calls to GetHashCode and three calls to CompareTo for each type in my discriminated union: one for each type.
Is there a way to code the GetHashCode override with just a single call to GetHashCode? Same question for CompareTo? All of the types in my discriminated union implement ICompareable.
[<CustomEquality;CustomComparison>]
type MyType =
| Bool of bool
| Str of string
| Float of float
override this.Equals(arg) =
let epsilon = 0.1
match arg with
| :? MyType as other ->
match this, other with
| Bool(a), Bool(b) -> a = b
| Str(a), Str(b) -> a = b
| Float(a), Float(b) -> Math.Abs(a - b) < epsilon
| _ -> false
| _ -> false
override this.GetHashCode() =
match this with
// Three calls to GetHashCode. I'd like only one
| Bool(a) -> a.GetHashCode()
| Str(a) -> a.GetHashCode()
| Float(a) -> a.GetHashCode()
| _ -> 0
interface System.IComparable with
member this.CompareTo arg =
match arg with
| :? MyType as other ->
match this, other with
// Three calls to CompareTo. I'd like only one
| Bool(a), Bool(b) -> a.CompareTo(b)
| Str(a), Str(b) -> a.CompareTo(b)
| Float(a), Float(b) -> a.CompareTo(b)
| _ -> 0
| _ -> 0
You could define a helper property that extracts the contents of the DU as obj
:
member this.Value =
match this with
| Bool(b) -> box b
| Str(s) -> box s
| Float(f) -> box f
Then you can implement GetHashCode
just by getting the value (which involves some boxing, so it will be a bit slower) and calling the GetHashCode
on the returned object:
override this.GetHashCode() =
this.Value.GetHashCode()