Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why was IEquatable T not made contravariant in T for C# 4.0?

Tags:

c#

c#-4.0

IEquatable<T> could have been declared to be contravariant in T, since it only uses T in an input position (or, equivalently, U being a subtype of T should imply that IEquatable<T> is [a subtype of] IEquatable<U>).

So, why did the BCL team not annotate it (for C# 4.0) with the 'in' keyword, as they did with many other generic interfaces (like the entirely analogous IComparable)?

like image 300
Khalid Khan Avatar asked Jul 20 '10 11:07

Khalid Khan


People also ask

What is contravariant c#?

C# Contravariance Cotravariance allows a method with the parameter of a base class to be assigned to a delegate that expects the parameter of a derived class. Continuing with the example above, add Method3 that has a different parameter type than delegate: Example: Contravariance with Delegte.

Can you be declared as Contravariant?

A type can be declared contravariant in a generic interface or delegate only if it defines the type of a method's parameters and not of a method's return type. In , ref , and out parameters must be invariant, meaning they are neither covariant nor contravariant.


2 Answers

I think this is mainly for a philosophical reason rather than a technical limitation–as it's perfectly possible to simply annotate the interface. IEquatable<T> is meant to compare objects of the same type for exact equality. An instance of a superclass is not usually considered equal to an instance of a subclass. Equality in this sense implies type equality too. This is a bit different from IComparable<in T>. It can be sensible to define a relative sort order across different types.

To quote MSDN page on IEquatable<T>:

Notes to Implementers:

Replace the type parameter of the IEquatable<T> interface with the type that is implementing this interface.

This sentence further demonstrates the fact that IEquatable<T> is meant to work between instances of a single concrete type.

like image 139
mmx Avatar answered Nov 01 '22 16:11

mmx


Inheritable types should generally not implement IEquatable<T>. If IEquatable<T> included a GetHashCode() method, one could define the semantics of IEquatable<T> to say that items should compare equal when examined as T's. Unfortunately, the fact that IEquatable<T> is bound to the same hash code as Object.Equals means that in general IEquatable<T> has to implement essentially the same semantics as Object.Equals.

Consequently, if an implementation of IEquatable<BaseClass> does anything other than call Object.Equals within it, a derived class which overrides Object.Equals and GetHashCode() and does not re-implement IEquatable<BaseClass> will end up with a broken implementation of that interface; an implementation of IEquatable<BaseClass> which simply calls Object.Equals will work just fine, even in that scenario, but will offer no real advantage over a class which doesn't implement IEquatable<T>.

Given that inheritable classes shouldn't be implementing IEquatable<T> in the first place, the notion of covariance is not relevant to proper implementations of the interface.

like image 20
supercat Avatar answered Nov 01 '22 15:11

supercat