How to override GetHashCode and CompareTo for Discriminatory Union in F #?

I have a simple F # discriminatory union that combines bool, string and float. I want to override Object.Equals (arg) of this union so that I can include epsilon to account for precision errors when checking for float equality. The compiler complained that if I override this.Equals (arg), I should also override this.GetHashCode () and this.CompareTo (arg). I have no special functionality for overriding, so I would just like to name the standard versions of these methods. In my implementation now, I have three calls to GetHashCode and three calls to CompareTo for each type in my discriminatory union: one for each type.

Is there a way to code the GetHashCode override with just one call to GetHashCode? Same question for CompareTo? All types in my discriminatory 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

      

+3


source to share


1 answer


You can define a helper property that retrieves the content 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 GetHashCode

only implement by getting the value (which is associated with some boxing, so it will be a little slower) and calling GetHashCode

on the returned object:

override this.GetHashCode() =
  this.Value.GetHashCode()

      

+5


source







All Articles