7

I have a book that explains contravariance/covariance as follows :

  • a delegate can have more specific parameter types than its method target. This is called contravariance
  • the return type of a delegate can be less specific than the return type of its target method. This is called covariance

And, this is an example.

using System;

delegate void StringAction(string s);
delegate object ObjectRetriever();

class Test
{
    static void Main()
    {
        StringAction sa = new StringAction(ActionObject);
        sa("hello");

        ObjectRetriever o = new ObjectRetriever(RetrieveString);
        object result = o();
        Console.WriteLine(result);
    }


    static string RetrieveString() {return "hello";}

    static void ActionObject(object o)
    {
        Console.WriteLine(o);
    }
}

I thought in order to use covariance/contravariance, one needs to use new as is shown in the example, but I seem to get the same result with sa = ActionObject and o = RetrieveString. (I tested with Mono).

  • Then, why the writer uses new to explain covariance/contravariance?
  • What's the theory behind the covariance/contravariance idea? Is it just a fancy name describing object x = Everything inherit from object? Where is this weird name come from? What's the usage for it?
prosseek
  • 182,215
  • 215
  • 566
  • 871
  • 1
    I find this post pretty useful - http://stackoverflow.com/questions/2184551/difference-between-covariance-contra-variance – prosseek Jul 23 '11 at 02:55

4 Answers4

23

I have a book that explains contravariance/covariance as follows ...

That is not a very good explanation of variance. It is left completely unclear precisely what it is that is called "covariance" and "contravariance".

The thing that actually is variant is never mentioned. The thing that is contravariant is the mapping from a type to a delegate with a parameter of that type. Contravariance is a property of mappings and relationships.

Try reading this and see if you understand it any better:

http://blogs.msdn.com/b/ericlippert/archive/2007/10/19/covariance-and-contravariance-in-c-part-three-member-group-conversion-variance.aspx

I thought in order to use covariance/contravariance, one need to use new as is shown in the example, but I seem to get the same result ...

Ever since C# 2.0 you can say either "d = M" or "d = new D(M)" -- the compiler simply recognizes them as two different ways to write the same thing.

why the writer uses new to explain covariance/contravariance?

I don't know.

What's the theory behind the covariance/contravariance idea?

The theory is that if you have an ordering relationship -- that is, X is bigger than Y if it is legal to say X x = (Y)y -- and you have a mapping that preserves the ordering relationship, then the mapping is covariant. If it reverses the ordering relationship, it is contravariant.

For example, suppose Animal is a bigger type than Giraffe. So you can assign an object of type Giraffe to a variable of type Animal. Animal > Giraffe.

Now make a mapping from a type T to a method M-that-takes-a-T and to a delegate type D-that-takes-a-T.

You can assign a method M-that-takes-an-Animal to a variable of type D-that-takes-a-Giraffe. D(Giraffe) > M(Animal) but Animal > Giraffe. The relationship is reversed; the mapping is contravariant.

Is it just a fancy name describing object x = Everything inherit from object?

No. It is related to that concept because object is a larger type than almost every other type. But what is actually variant is a mapping that preserves or reverses a size relationship.

Try reading this and see if it helps.

http://blogs.msdn.com/b/ericlippert/archive/2009/11/30/what-s-the-difference-between-covariance-and-assignment-compatibility.aspx

Where is this weird name come from?

Category theory.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
2

The best info describing covariance/contravariance in the C# I've ever seen is series of blog posts by Eric Lippert here. See starting from the bottom of the list, eleven-parts series.

It is somewhat hard to read sometimes. But it explains everything you could ask in the beginning. :)

It was written prior to actual C# 4.0 implementation, so some discussion of the syntax is obsolete, but everything else seems to be implemented just as described.

Ivan Danilov
  • 14,287
  • 6
  • 48
  • 66
1

Here's a great wiki article on it: here

It's more a matter of which direction the funnel pours and setting the width of the funnel at an appropriate level...

Rikon
  • 2,688
  • 3
  • 22
  • 32
-1

No idea what you mean in your first question.

The second question can be answered by suggesting looking at casting. Contravariance is allowing class A which has an extended class B be stored as a class B.

Contravariance

class A {
}

class B : public A {
}

B obj = new A();

Covariance is allowing class B which extends class A but stored as a class A.

Covariance

class A {
}

class B : public A {
}

A obj = new B();
Suroot
  • 4,315
  • 1
  • 22
  • 28
  • You're plainly wrong. Covariance/contravariance deals with generic types. – Ivan Danilov Jul 23 '11 at 02:07
  • @Suroot : I wanted to ask why the writer uses `ObjectRetriever o = new ObjectRetriever(RetrieveString);` when `ObjectRetrieve o = RetrieveString` works. – prosseek Jul 23 '11 at 02:07
  • Well, I was probably too harsh. My bad, sorry. In general sense variance is about type orderings. In C# though it mainly associates with generics and delegates. Inherited classes is very trivial case and I didn't think of it as a covariance case at all before :) – Ivan Danilov Jul 23 '11 at 02:11
  • 1
    @Ivan One of the implementations is of Generics, but it refers to general conversions of wider -> narrow, narrow -> wider data types. The main place that I've seen this is in return types. NOTE: This is not the only case, but (imho) is usually the most widely used form of it. – Suroot Jul 23 '11 at 02:12
  • 1
    Ivan is correct. **What you are describing is absolutely not what variance is.** Assignment compatibility is *the ordering relation* relevant to variance, but what is variant is a *mapping* that *preserves or reverses* that relation. If you want to understand the difference between *assignment compatibility* and *variance*, here's my article on the subject: http://blogs.msdn.com/b/ericlippert/archive/2009/11/30/what-s-the-difference-between-covariance-and-assignment-compatibility.aspx – Eric Lippert Jul 23 '11 at 05:36
  • @Ivan: There are a number of different ways that variance impacts C# and only one of them -- generic type variance -- deals specifically with generic type mappings. The original poster's question is about *variant conversions from method groups to delegates*. C# also has *variant conversions on array types*. Languages like C++ have *return type covariance for virtual method implementations* and some other languages have virtual parameter contravariance. There are lots of ways things can be variant that don't involve generics. – Eric Lippert Jul 23 '11 at 05:43
  • @Eric Lippert: Thanks Eric. I understood my mistake when had taken a look at wiki's definition. And about this particular case: if we treat assignment operator as function of two arguments (informally of course) like `assign(out l, in r)` then it will be covariant on first arg and contravariant on second. It is far-fetched, but seems to be valid, isn't it? Can't be written in C# though due to `out` keyword has not write-only semantic, but nevertheless. – Ivan Danilov Jul 23 '11 at 06:45
  • To not confuse others and be more precise. It's not a function that would be contravariant but rather uplifting mapping from input type `TIn` to function `void assign(TOut l, TIn r)`. Same with covariance. P.S. Not sure it became clearer though... Eric, you definitely have great talent in explaining these kind of things! It seems not-so-hard strictly until you tries to explain to others. – Ivan Danilov Jul 23 '11 at 08:25
  • @Ivan: You're correct; the reason that out parameters are not legal for covariance is because behind the scenes they are actually read-write "ref" parameters. "out" is just a convention of the C# language, not of the actual type system. – Eric Lippert Jul 23 '11 at 13:43