-
Notifications
You must be signed in to change notification settings - Fork 833
Description
(Reposted from github.com/fsharp/fsharp)
I know that nan = nan and nanf = nanf both return false.
But nan.Equals(nan) and nanf.Equals(nanf) return true. These are intended results and this also applies when nan or nanf is contained in another structural type such as a union.
The .NET Guidelines also say that Equals, GetHashCode and CompareTo should be consistent. That is, two values that are equal should be equal as per Equals, should return the same hash and CompareTo should return 0.
F# types adhere to this except for the following case when a single/float32 or double/float that is NaN is a value of a structural type such as a union, which is nested in another structural type such as a union or record that has at least one type parameter.
Here is sample code that shows the inconsistent behavior:
type UnionWithFloat = UnionWithFloat of float
type GenericUnion<'value> = GenericUnion of 'value
type NonGenericUnion = NonGenericUnion of UnionWithFloat
let leftGenericUnion = GenericUnion (UnionWithFloat nan)
let rightGenericUnion = GenericUnion (UnionWithFloat nan)
let leftNonGenericUnion = NonGenericUnion (UnionWithFloat nan)
let rightNonGenericUnion = NonGenericUnion (UnionWithFloat nan)
let comparableLeftGenericUnion = leftGenericUnion :> System.IComparable<GenericUnion<UnionWithFloat>>
let comparableLeftNonGenericUnion = leftNonGenericUnion :> System.IComparable<NonGenericUnion>
let genericUnionsEqual = leftGenericUnion.Equals(rightGenericUnion) // false!
let nonGenericUnionsEqual = leftNonGenericUnion.Equals(rightNonGenericUnion) // true
let genericUnionsHashCodesEqual = leftGenericUnion.GetHashCode() = rightGenericUnion.GetHashCode() // true
let nonGenericUnionsHashCodesEqual = leftNonGenericUnion.GetHashCode() = rightNonGenericUnion.GetHashCode() //true
let genericUnionsComparisonEqual = comparableLeftGenericUnion.CompareTo(rightGenericUnion) = 0 // true
let nonGenericUnionsComparisonEqual = comparableLeftNonGenericUnion.CompareTo(rightNonGenericUnion) = 0 // trueThe inconsistent result is the following line:
let genericUnionsEqual = leftGenericUnion.Equals(rightGenericUnion) // false! All the other ways of comparison correctly return true.
Note that this also applies to single/float32 and records. And you only see the inconsistent results when the type is generic (GenericUnion here), which nests another type (UnionWithFloat here). I have not tested this for more types or constellations. This was tested with F# 3.1 if this makes a difference.
I would be nice if you could fix this as it had me scratching my head for some time until I could pin down when this happens. It would also be nice if you could verify that the results are consistent for all possible types in all constellations in F#, whether generic and/or nested.
Metadata
Metadata
Assignees
Labels
Type
Projects
Status