17

C# 4.0 is going to support covariance and contravariance. But I don't clearly understand the benefits of this new feature. Can you explain me (clearly) why we need it?

Michael Myers
  • 188,989
  • 46
  • 291
  • 292
Delta76
  • 13,931
  • 30
  • 95
  • 128
  • Bart De Smet has a great blog entry about covariance & contravariance [here](http://bartdesmet.net/blogs/bart/archive/2009/04/13/c-4-0-feature-focus-part-4-generic-co-and-contra-variance-for-delegate-and-interface-types.aspx). – Mike Thompson Sep 11 '09 at 03:19

4 Answers4

8

They just allow you to do some things that are conceptually valid, and formally acceptable, but aren't currently allowed because of language constraints. For example:

IEnumerable<int> ints = new List<int> { 1, 2, 3 };

Action<IEnumerable<object>> PrintThings =
    x => { foreach(var thing in x) Console.WriteLine(thing); };

PrintThings(ints); // doesn't compile right now :(  will compile in 4.0

There's no fundamental reason why this can't work or shouldn't work; it just happens to not be allowed in the language. By allowing it, you make programmers' lives easier when such an operation would be natural for them to perform.

mqp
  • 70,359
  • 14
  • 95
  • 123
  • The fundamental reason the above won't work before 4.0 is that there is no way in the syntax to allow it without losing type safety. If you allow it for your example, then you necessarily also allow it for examples where type safety is not preserved. – Eddie Apr 29 '09 at 17:42
  • That's right, which is why they're adding the new "in" and "out" keywords to support it (and IEnumerable will be to allow this scenario.) – mqp Apr 29 '09 at 18:12
6

There are alot of misconceptions out there as to how and what will work in 4.0. The best explanation I've read so far was written my Marc Gravell. See his blog post here:

http://marcgravell.blogspot.com/2009/02/what-c-40-covariance-doesn-do.html

Just to reiterate, alot of ppl think this will work in 4.0:

public class Base{}
public class Derived : Base {}

..in some other class

List<Derived> derived....

public void Method(List<Base> b){}

Even in 4.0, you will not be able to pass the List into this method. As Marc points out, that's what Generic constraints are there for, and can be done since 2.0

BFree
  • 102,548
  • 21
  • 159
  • 201
  • This seems like a strange non sequitur to me. The only reason you can't pass the List is because Lists are mutable; of course you can't pass like that, since adding items to it would break the type restrictions on it. – mqp Apr 29 '09 at 16:04
  • @mquander: A strange non-sequitur? The API (pre 4.0) has nothing to say, "you can do this operation only if the object is immutable". – Eddie Apr 29 '09 at 17:40
  • My point is simply that the fact that List allows you to add and change Ts is why it doesn't make sense. If you tried to add the "out" parameter on IList to allow this, those methods could no longer work as intended. – mqp Apr 29 '09 at 18:16
3

One of the benefits that, in my opinion, covariance is going to help a lot is with Generics.

I encountered several situations where one needs to explicitly use Cast to convert a specific type to it's base.

class Foo { }
class Bar : Foo { }

// ...

IEnumerable<Foo> foos = new List<Foo>();
IEnumerable<Bar> bars = new List<Bar>();

foos = bars.Cast<Foo>();

// C# 4.0
foos = bars;

Here's a good reference on the subject.

bruno conde
  • 47,767
  • 15
  • 98
  • 117
1

There's a good write up that talks about this issue here.

Andrew Flanagan
  • 4,267
  • 3
  • 25
  • 37