Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing IComparable<NotSelf>

Tags:

c#

icomparable

This might be a trivial question, but I didn't find any information about this: is it "harmful" or considered bad practice to make a type T implement IComparable<S> (T and S being two different types)?

Example:

class Foo : IComparable<int>
{
    public int CompareTo(int other)
    {
        if (other < i) return -1;
        if (other > i) return 1;

        return 0;
    }

    private int i;
}

Should this kind of code be avoided, and if yes, why?

like image 491
Luc Touraille Avatar asked Mar 29 '10 16:03

Luc Touraille


3 Answers

I would at least consider it "odd" - in particular at that point the comparison isn't going to be symmetric, which is usually part of normal comparison contracts.

If there's a particular situation where it's simpler than any other implementation of what you want to do, that would be okay - but I can't say I've ever come across such a situation. Comparisons like this are almost always used for sorting a homogeneous collection or something similar.

Did you have a particular situation in mind, or is it just a "for interest" question?

like image 175
Jon Skeet Avatar answered Nov 01 '22 09:11

Jon Skeet


It is fancy to implement such things. But it is not a good practice.

Imagine you see some code like this:

Foo x = new Foo();

if( x.compareTo(15) > 0)
{
  //blah blah
}

You will say "oh my god! how to compare 15 to x?"? This will make code less readable..

It is better to add compare as function like this: public int IsMoreThanPrivateI(int x);

like image 45
Yousf Avatar answered Nov 01 '22 07:11

Yousf


I can see a use for comparing objects of different classes, but I don't think IComparable(of T) is the right basis. For such comparisons to really work, the objects must have a common canonical form, which implies that they all be derived from a common ancestor or implement a common interface. I would further suggest that this common base include a SecondChanceCompareTo method, and normal compare method should, if it doesn't recognize the precise type to which it's being compared, pass itself to the passed-in object's SecondChanceCompare method.

As an example of where this type of thing might be useful, imagine a family of classes that store strings; a string might be stored as a straightforward String object, but some strings might be stored as a character and repetition count, others might be stored as a reference to a longer string along with a starting offset and length, etc. It would be possible to compare two string objects by converting them to type "String" and then doing the comparison, but there are many scenarios where better means of comparison exist. For example, if one string is stored as "Character 'Z' repeated 100,000 times" and the other string is stored as "Literal string 'Dog'", the former string could compare itself to the latter by observing that the latter's first character was less than 'Z'.

Note that the basic 'literal string' object might not know how to compare itself to the 'repeated character' string object except by converting the latter to a literal string (an expensive operation), but it could call the latter's "SecondChanceCompare" method, which would know how to compare itself to a literal string.

like image 1
supercat Avatar answered Nov 01 '22 08:11

supercat