Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I have a type that's both, covariant and contravariant, i.e. fully fungible/changeable with sub and super types?

Can I have a type (for now forgetting its semantics) that can be covariant as well as contravariant?

for example:

public interface Foo<in out T>
{
    void DoFooWith(T arg);
}

Off to Eric Lippert's blog for the meat and potatoes of variance in C# 4.0 as there's little else anywhere that covers adequate ground on the subject.


I tried it out anyway, not only does it not allow that, but it tells me I am missing the whole point. I need to understand the link between read-only, write-only and variance.

I guess I got some more reading to do.

But any short, epiphany inducing answers are welcome, meanwhile.

like image 759
Water Cooler v2 Avatar asked May 11 '10 10:05

Water Cooler v2


People also ask

What are covariance and contravariance in typescript?

Generic type parameters support covariance and contravariance to provide greater flexibility in assigning and using generic types. When you're referring to a type system, covariance, contravariance, and invariance have the following definitions. The examples assume a base class named Base and a derived class named Derived.

Are generic type parameters covariant or contravariant?

An invariant generic type parameter is neither covariant nor contravariant. You cannot assign an instance of List<Base> to a variable of type List<Derived> or vice versa. Covariant type parameters enable you to make assignments that look much like ordinary Polymorphism, as shown in the following code.

Can a vector have both a covariant and a contravariant basis?

I understand that, in curvilinear coordinates, one can define a covariant basis and a contravariant basis. It seems to me that any vector can be decomposed in either of those basis, thus one can have covariant components and contravariant components of the same vector, depending on the chosen basis.

What is the difference between contravariant functors and smooth functions?

The first is that vectors whose components are covariant (called covectors or 1-forms) actually pull back under smooth functions, meaning that the operation assigning the space of covectors to a smooth manifold is actually a contravariant functor.


1 Answers

No, you cannot do that.

Suppose that were legal. You make an IFoo<Giraffe>. Since IFoo is covariant in T, you can convert it via typesafe reference conversion to IFoo<object>. Since it is contravariant, you can convert that to IFoo<Banana>. What possible semantics are there for IFoo<T> such that it makes sense to be able to convert an IFoo of Giraffes to an IFoo of Bananas via reference conversion? Giraffes and Bananas have nothing in common other than being reference types. You cannot possibly have a method on IFoo<Banana> that returns a Banana, because it might actually be an implementation of IFoo<Giraffe>; how would the author of the implementation know to hand out a Banana? You cannot possibly have a method on IFoo<Banana> that takes a Banana for the same reason; the implementor of IFoo<Giraffe> is expecting you to hand him a Giraffe.

Here's another way of looking at it:

  • "in T" means (roughly) "T appears only in input positions".
  • "out T" means (roughly) "T appears only in output positions".

Therefore "in out T" would mean... what? As we've seen already, it can only mean "T does not appear at all in any method or property." What's the point of making a generic type in T where you never use T?

like image 187
Eric Lippert Avatar answered Nov 13 '22 07:11

Eric Lippert