Open
Description
From #513
The problem is that for concrete types, the implementation of IStructuralEquatable optimizes standard types, which means that the IEqualityComparer is unused.
The following example shows this by using a specialized IEqualityComparer to try to do an uppercase string comparison.
type A = { A : string }
type B<'a> = { B : 'a }
[<EntryPoint>]
let main argv =
let a1, a2 = { A = "Hello"}, { A = "HELLO" }
let b1, b2 = { B = "Hello"}, { B = "HELLO" }
let compareStringWithUpper=
let toupper (s:string) = s.ToUpper ()
{ new IEqualityComparer with
member this.GetHashCode item =
match item with
| :? string as s -> (toupper s).GetHashCode ()
| _ -> failwith "Not in this example..."
member this.Equals (lhs, rhs) =
match lhs, rhs with
| (:? string as s1), (:? string as s2) -> (toupper s1).Equals(toupper s2)
| _ -> failwith "Not in this example..." }
let a_is_good = (a1 :> IStructuralEquatable).Equals(a2, compareStringWithUpper)
let b_is_good = (b1 :> IStructuralEquatable).Equals(b2, compareStringWithUpper)
printfn "A is %s" <| if a_is_good then "Good" else "Bad"
printfn "B is %s" <| if b_is_good then "Good" else "Bad"
if a_is_good <> b_is_good then
printfn "But worse than those results are that they are inconsistent!"
With the output
A is Bad
B is Good
But worse than those results are that they are inconsistent!
I think the implementation of IStructuralEquatable.Equals shouldn't used inlined IL, but rather always defer back to supplied IEqualityComparer.
Fixing this before #513 is implemented would have a performance impact.
Metadata
Metadata
Assignees
Labels
Type
Projects
Status
In Progress