C#: Comparison operator overloading and spaceship operator

Lets consider I have a class Employee which has  Name and JobGrade fields. I want to overload the comparison operators for this class so that it can participate in all types of comparison including <. <=, ==, >=, != and Equals. I want to translate the comparison in-between two Employee objects to be a comparison between the JobGrade . Since I do not want to write the comparison logic each time, typically I'd implement the comparison in one method and from comparison operator overloading methods call this common method. So in C# I'd do something like.

 class Employee{    public Employee(string name, int jobGrade){        Name = name;        JobGrade = jobGrade;    }    public string Name;    public int JobGrade;

     public static bool operator <(Employee emp1, Employee emp2){        return Comparison(emp1, emp2) < 0;    }    public static bool operator >(Employee emp1, Employee emp2){        return Comparison(emp1, emp2) > 0;    }    public static bool operator ==(Employee emp1, Employee emp2){        return Comparison(emp1, emp2) == 0;    }    public static bool operator !=(Employee emp1, Employee emp2){        return Comparison(emp1, emp2) != 0;    }    public override bool Equals(object obj){        if (!(obj is Employee)) return false;        return this == (Employee)obj;    }    public static bool operator <=(Employee emp1, Employee emp2){        return Comparison(emp1, emp2) <= 0;    }    public static bool operator >=(Employee emp1, Employee emp2){        return Comparison(emp1, emp2) >= 0;    }    public static int Comparison(Employee emp1, Employee emp2){        if (emp1.JobGrade < emp2.JobGrade)            return -1;        else if (emp1.JobGrade == emp2.JobGrade)            return 0;        else if (emp1.JobGrade > emp2.JobGrade)            return 1;        return 0;    }}

This is kind of huge as I have to overload each comparison operator individually even though what I want is to just make Employee object comparable to any other Employee object. What happens is as follows

  1. public static bool operator <=(Employee emp1, Employee emp2) gets compiled to a method named bool op_LessThanOrEqual(Employee, Employee). Similiar naming convention is used for the other operators.
  2. On seeing the code emp1 <= emp2 the compiler emits code to call the method op_LessThanOrEqual

This makes overloading operators individually a requirement.

What if

In some languages like Ruby and also Perl (I am not that sure on perl) there is a concept of space ship operator <=>. This operator must return less than 0, equal to 0, greater than 0 based on whether the expression on the left is less than, equal-to or greater than that on the right (similiar to IComparable:CompareTo). If C# compiler supports the concept of the space-ship operator then we can simply overload this one operator and expect the compiler to emit code to call this operator for all comparison. So if C# supports this then the above code would look like

 class Employee{    public Employee(string name, int jobGrade){        Name = name;        JobGrade = jobGrade;    }    public string Name;    public int JobGrade;     public override bool Equals(object obj){        if (!(obj is Employee)) return false;        return this == (Employee)obj;    }    // same in the lines of IComparable:CompareTo
    publicstaticintoperator  <=>(Employee emp1, Employee emp2) {        if (emp1.JobGrade < emp2.JobGrade)            return -1;        else if (emp1.JobGrade == emp2.JobGrade)            return 0;        else if (emp1.JobGrade > emp2.JobGrade)            return 1;        return 0;    }}

In this case what'll happen is as follows

  1. public static int operator <=>(Employee emp1, Employee emp2) gets compiled to bool op_SpaceShip(Employee, Employee)
  2. On seeing emp1 <= emp2 the compiler emits code to call the method op_SpaceShip(emp1, emp2) <= 0
  3. On seeing emp1 != emp2 the compiler emits code to call the method op_SpaceShip(emp1, emp2) != 0
  4. Or generically emp1 op emp2 gets compiled to op_SpaceShip(emp1, emp2) op 0

Interfaces like IComparable already exists which needs the class to implement CompareTo which works exactly like <=> operator overloaded as above. If only the compiler directly made calls to this then the need for one to implement this interface and then make calls to this method gets removed.

The overloaded <=> acts as a filler. In case <= and => are already overloaded for a class then calls are made to these methods and for operators not overloaded like == and != calls are made to <=>.

Its not important (atleast to me) how we achieve this and can include ways like have a method CompareTo in Object in the same lines of Equals and make the compiler emits calls to it based on the operator getting used or use explicite <=> operator overloading. Either way the need to overload all 5 operators should be eliminated.