views:

375

answers:

5

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?

+5  A: 

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.

mquander
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
That's right, which is why they're adding the new "in" and "out" keywords to support it (and IEnumerable<T> will be <out T> to allow this scenario.)
mquander
+1  A: 

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

Andrew Flanagan
+3  A: 

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
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.
mquander
@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
My point is simply that the fact that List<T> allows you to add and change Ts is why it doesn't make sense. If you tried to add the "out" parameter on IList<T> to allow this, those methods could no longer work as intended.
mquander
+2  A: 

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
Still, the overuse of italics was a nice touch.
bzlm
Sorry :( forgot the class def
bruno conde
A: 

Bart De Smet has a great blog entry about covariance & contravariance here.

Mike Thompson