I was recently presented with a conundrum. We had constrained data valid for the domain in a record type. Sadly this record type contained a reference datatype, so built-in structural equality broke down as the reference type never was equal in the way we thought would make sense.
This gave me the opportunity to learn how you override the implementation of Equals and GetHashCode in F# which I was previously unfamiliar with.
This is the finished implementation of the record type, or one like it, rather:
[<CustomEquality>]
[<CustomComparison>]
type Structure =
{
Name: StructureName
Status: StructureStatus
Format: Regex
}
with
interface IComparable with
member this.CompareTo { Name = name; Status = status; Format = format } =
compare ( this.Name, this.Status, this.Format.ToString() ) (name, status, format.ToString())
interface IComparable with
member this.CompareTo obj =
match obj with
| null -> 1
| :? Structure as other -> (this :> IComparable<_>).CompareTo other
| _ -> invalidArg "obj" "not a Structure"
override this.Equals (o: obj) =
match o with
| :? Structure as os ->
(this.Name, this.Status, this.Format.ToString()) =
(os.Name, os.Status, os.Format.ToString())
| _ -> false
override this.GetHashCode() =
(this.Name, this.Status, thus.Format.ToString()).GetHashCode()
So yeah, ujse of pattern matching to determine data types in the non-generic functions and extensive use the built-in structural equality in tuples.
Very nice. With thanks to TeaDrivenDev and Isaac Abraham on Twitter (and this StackOverflow response)