Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Supporting both covariance and contravariance for a single type parameter [duplicate]

Possible Duplicate:
Covariance and Contravariance on the same type argument

You can declare a generic type parameter as covariant by using the out keyword:

interface ICovariant<out R>

You can declare a generic type parameter as contravariant by using the in keyword:

interface IContravariant<in R>

And you can also support both for different type parameters:

interface IVariant<out R, in A>

So why can't you suport both for a single type parameter?

like image 926
James Wiseman Avatar asked Jul 15 '11 15:07

James Wiseman


People also ask

What do contravariance and covariance enable?

In C#, covariance and contravariance enable implicit reference conversion for array types, delegate types, and generic type arguments. Covariance preserves assignment compatibility and contravariance reverses it.

What is covariance and contravariance in generics?

Covariance and contravariance are terms that refer to the ability to use a more derived type (more specific) or a less derived type (less specific) than originally specified. Generic type parameters support covariance and contravariance to provide greater flexibility in assigning and using generic types.

What is covariance and contravariance in Scala?

Covariance allows assigning an instance to a variable whose type is one of the instance's generic type; i.e. supertype. Contravariance allows assigning an instance to a variable whose type is one of the instance's derived type; i.e. subtype.

Why is contravariance useful?

This is mainly useful when using already defined standard interfaces. Covariance means that you can use IEnumerable<string> in place where IEnumerable<object> is expected. Contravariance allows you to pass IComparable<object> as an argument of a method taking IComparable<string> . So far, so good.


1 Answers

So why can't you suport both for a single type parameter?

Keep in mind that an interface can only be covariant in a type parameter if that type parameter is output-safe and an interface can only be contravariant in a type parameter if that type parameter is input-safe.

The syntax out T says that T is a covariant type parameter.

The syntax in T says that T is a contravariant type parameter.

As T is a covariant type parameter, it is by definition input-unsafe.

As T is a contravariant type parameter, it is by definition output-unsafe.

Therefore, T is input-unsafe and output-unsafe.

Consequently, T is prohibited in input positions, and T is prohibited in output positions.

Therefore, T can not appear in input positions nor in any output positions on any methods specified by the interface.

Consequently, T can not be used on the interface at all, and is pointless as a type parameter. Consequently, the language designers prohibit you from even including such a useless type marked as both covariant and contravariant on the interface to avoid the ugly

interface IFoo<in and out T> { }
Foo<T> : IFoo<T> { }

and then:

IFoo<Cat> cat = (IFoo<Animal>)new Foo<Dog>();

(If you need to read up on input-safe and output-safe, see 13.1.3.1 of the language specification.)

like image 139
jason Avatar answered Oct 11 '22 15:10

jason