You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Generic Record Types have different Equality semantics to concrete types #527
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.
Activity