views:

911

answers:

5

Can someone explain why there is the need to add an out or in parameter to indicate that a generic type is Co or Contra variant in C# 4.0?

I've been trying to understand why this is important and why the compiler can't just figure it out..

Thanks,

Josh

+1  A: 

The in and out keywords have been keywords since C# 1.0, and have been used in the context of in- and out- parameters to methods.

Covariance and contravariance are constraints on how one can implement an interface. There is no good way to infer them - the only way, I think, is from usage, and that would be messy and in the end it wouldn't work.

Justice
It *could* be inferred though. The compiler checks whether you're using an "in" type parameter in an "out" position, for instance - so it could just have two flags: "can be in" and "can be out" and knock them off when looking through the methods in the interface.
Jon Skeet
+17  A: 

Eric Lippert, who works on the langauge, has a series of posts on msdn that should help clarify the issues involved:
http://blogs.msdn.com/ericlippert/archive/tags/Covariance+and+Contravariance/default.aspx

When reading the articles shown at that link, start at the bottom and work up.

Eventually you'll get to #7 (Why do we need a syntax at all?).

Joel Coehoorn
I've read the series as it went along, and I don't remember seeing anything explaining why it would have to be explicit (as opposed to inferred). Do you have a specific post in mind?
Jon Skeet
No, I just remember him talking a lot about inference, and even discussing what the syntax might look like and why. Reading through the list again, #7 (title: why do we need a syntax at all?) looks promising.
Joel Coehoorn
@Joel: That post is exactly the right answer. I suggest you edit your answer to refer to it directly :)
Jon Skeet
Was already working on it :)
Joel Coehoorn
JoshBerke
Josh: I had nothing to do with it really :) (Hence deleting my inadequate answer.) Side-note: Eric really rocks...
Jon Skeet
+6  A: 

We don't actually need them, any more then we need abstract on classes or both out and ref. They exist just so that we, as programmers, can make our intention crystal clear, so that maintenance programmer know what we are doing, and the compiler can verify that we are doing it right.

James Curran
+6  A: 

Well, the main problem is that if you have a class hierarchy like:

   class Foo { .. } 

   class Bar : Foo { .. }

And you have an IEnumerator<Bar>, you can't use that as an IEnumerator<Foo> even though that would be perfectly safe. In 3.5 this forces a large number of painful gyrations. This operation would always be safe but is denied by the type system because it doesn't know about the covariant use of the generic type parameter. IEnumerator<Bar> can only return a Bar and every Bar is a Foo.

Similarly, if you had an IEqualityComparer<Foo> it can be used to compare any pair of objects of type Foo even if one or both is a Bar, but it cannot be cast into an IEqualityComparer<Bar> because it doesn't know about the contravariant use of the generic type parameter. IEqualityComparer<Foo> only consumes objects of type Foo and every Bar is a Foo.

Without these keywords we're forced to assume the generic argument can occur as both an argument to a method and as the result type of a method, and so we can't safely allow either of the above conversions.

With them, the type system is free to allow us to safely upcast and downcast between those interfaces in the direction indicated by the keyword and we get errors indicating when we would violate the discipline required to ensure that safety.

Edward Kmett
A: 

Jon and Joel both provided a pretty complete answer to this, but the bottom line is that they aren't so much needed by the compiler but rather help guarantee the safety of the implementation by explicitly indicating the variance of the parameter. This follows a very similar pattern to requiring the out or ref keyword at both the calling site and the declaration site.

Scott Dorman