Click here to Skip to main content
13,706,637 members
Click here to Skip to main content
Add your own
alternative version

Tagged as

Stats

4.6K views
Posted 17 Feb 2016
Licenced CPOL

Equality and Equivalence

, 17 Feb 2016
Rate this:
Please Sign up or sign in to vote.
Equality and Equivalence

Note: This is related to a twitter conversation that started with Jared Parsons here. I felt this was worth more than 140 characters.

Let’s pose Jared’s original question:

“Should IEquatable<T>.Equals and IComparable<T>.CompareTo always agree on equality?”

I continue to assert “Not always”. IComparable<T> determines if two objects are equivalent based on the sorting order. IEquatable<T> determines if they are equal.

The example I gave on twitter was a Person class: Two people may have the same name, and yet not be equal. Some people disagreed with me, saying that it would be better to provide different sort order via different IComparer implementations, and leave equality to match all observable properties on an object.

It’s true that in many applications, two objects that compare as equivalent using IComparable<T>.CompareTo() will compare as equal using IEquatable<T>.Equals().

It should also always be true that if two objects are considered equal by calling IEquatable<T>.Equals(), they must be equivalent as seen by IComparable<T>.CompareTo().

However, there will continue to be examples where two objects are equivalent (as determined by IComparable<T>.CompareTo(), but not equal (as determined by IEquatable<T>.Equals().)

Let’s consider a larger example. Here I have a Star class, from an Astronomy based application:

// Ordered from coolest to hottest, so the natural order in an enum
// would go from coolest to hottest.
public enum SpectralScale
{
   T,
   L,
   M,
   K,
   G,
   F,
   A,
   B,
   O
}
public class Star : IComparable<Star>, IEquatable<Star>
{
   public SpectralScale SpectralType { get; set; }
   public int SpectralHeat { get; set; }

   // Usually displayed using Roman Numerals from I thru V
   public int LuminosityClass { get; set; }
   public string Name { get; set; }

   public override string ToString() => $"{SpectralType}{SpectralHeat}{ToRoman(LuminosityClass)}";

   private string ToRoman(int luminosityClass)
   {
       string[] numerals = { "", "I", "II", "III", "IV", "V" };
       return numerals[luminosityClass];
   }

   public int CompareTo(Star other)
   {
       int typeCompare = this.SpectralType.CompareTo(other.SpectralType);
       if (typeCompare != 0)
           return typeCompare;
       int heatCompare = this.SpectralHeat.CompareTo(other.SpectralHeat);
       if (heatCompare != 0)
           return heatCompare;
       return this.LuminosityClass.CompareTo(other.LuminosityClass);
   }

   public bool Equals(Star other)
   {
       return ((this.CompareTo(other) == 0) &&
           this.Name == other.Name);
   }
}

In this application, stars are classified using the Morgran-Keenan (MK) system. You can read more here. In this classification, stars are classified using the heat generated, and their luminosity. In this classification system, many stars may have equivalent classifications (the sun’s value is G2V). However, the stars with the same value are not equal; they are different stars.

You can see this in the implementation of Equals: It checks CompareTo, and then adds an additional comparison.

To reiterate: Stars with the same classification are equivalent. They may not be equal. (They are only equal if the object references refer to the same star in the sky).

You will find many examples of this behavior in many fields: a circle and a square may be equivalent (based on their area), but they are not equal. We may sort contestants in a sporting event by points: ties don’t imply equality.

Equivalence may not mean Equality

So many of the real world code we write contains classes where equivalence and equality are the same in practice that we forget that this is not a universal truth. Write the code you mean. And be careful about assumptions.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Bill Wagner
Architect Bill Wagner Software LLC
United States United States
Bill Wagner is one of the world's foremost C# developers and a member of the ECMA C# Standards Committee. He is President of the Humanitarian Toolbox, has been awarded Microsoft Regional Director and .NET MVP for 10+years, and was recently appointed to the .NET Foundation Advisory Council. Wagner currently works with companies ranging from start-ups to enterprises improving the software development process and growing their software development teams.

You may also be interested in...

Comments and Discussions

 
Questionbeating a dead horse ? Pin
Chris A Clarke26-Feb-16 6:37
memberChris A Clarke26-Feb-16 6:37 
AnswerRe: beating a dead horse ? Pin
Bill Wagner26-Feb-16 7:18
professionalBill Wagner26-Feb-16 7:18 
GeneralRe: beating a dead horse ? Pin
Chris A Clarke26-Feb-16 10:46
memberChris A Clarke26-Feb-16 10:46 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Cookies | Terms of Use | Mobile
Web01-2016 | 2.8.180920.1 | Last Updated 17 Feb 2016
Article Copyright 2016 by Bill Wagner
Everything else Copyright © CodeProject, 1999-2018
Layout: fixed | fluid