5

In most places I read that it is a good idea to inherit from both IComparable and IComparable<T> in your classes to provide compatibility with non-generic collections. My question is why IComparable<T> doesn't inherit from IComparable by default then? The backward compatibility would be achieved this way.

For example, IEnumerable<T> does inherit from IEnumerable, so why don't do the same thing with IComparable? I read about variances, but I still don't really understand why it was designed that way. I tried to create a small example with interfaces with the same architecture, and it works as intended.

Edit: Also, Microsoft documentation states the following: Generic interfaces can inherit from non-generic interfaces if the generic interface is contravariant, which means it only uses its type parameter as a return value. In the .NET Framework class library, IEnumerable<T> inherits from IEnumerable because IEnumerable<T> only uses T in the return value of GetEnumerator and in the Current property getter.

But despite that, one can inherit IComparable from IComparable<T> just fine (if you create interfaces with same architectures, that is).

  • Probably [gives an idea](https://stackoverflow.com/a/16492085/11683). (And it would not be applicable to IEnumerable.) – GSerg Sep 23 '19 at 15:19
  • I saw that question, when I tried to look up mine. Though it just describes the possible implementation of a class with both interfaces. My question is why `IComparable` doesn't inherit from `IComparable` in the first place. – Andrew Petukhov Sep 23 '19 at 15:23
  • This question can only be answered by the designers of the language. Other answers will be guesses and supposition. See for example the Meta question [Is asking “why” on language specifications still considered as “primarily opinion-based” if it can have official answers?](https://meta.stackoverflow.com/q/323334/215552) – Heretic Monkey Sep 23 '19 at 15:25

2 Answers2

0

Try it yourself if type is not specified then class which implement generic interface would also need to implement default type method

    public interface IFoo
    {
        void Foo(object o);
    }

    public interface IFoo<T> : IFoo
    {
        void Foo(T o);
    }

which turns into

public class Foo : IFoo<int>
    {
        void IFoo<int>.Foo(int o)
        {
            throw new System.NotImplementedException();
        }

        void IFoo.Foo(object o)
        {
            throw new System.NotImplementedException();
        }
    }

In this case you implement one interface with one method and it appear you must implement two methods wheres you inherit from typed interface

miechooy
  • 3,178
  • 12
  • 34
  • 59
0

This comes down to a Language Design decision, so short of a word of devs we can only guess.

One good reason is certainly that one is generic, the other not. Generics are inherently superior to the non-generic solution (wich means using object as a type) as they maintain type safety at compile time. So there was propably an intentional choice to break with the pre-generic version. To avoid downwards compatibiltiy. Notice how most classes that implement the Generic Version, do not implement it's non-generic counterpart. Really fundamental and old stuff like string are the exception - because they could not remove the old Interface, only add new ones.

With enumerators, the need seems less extreme. Enumerators are usually generated instead off or from a collection and fore purely reading processing. So you either have a fixed type to cast too or a fixed type to use in the Enumerator.

Another reason is propably that code that uses IComparable either explicitly demands it (type constraints) or consists of stuff made from it - and is itself generic by definition. Most often it is used for sort functions in generic collections. It is possible they did not want to use old collections anymore. And not supporting IComparable on Dictionary was certainly a good choice to get HashTable (it's pre-generic counterpart) out of circulation.

Christopher
  • 9,634
  • 2
  • 17
  • 31