Question

My first encounter with the terms: output-safe, input-safe, output-unsafe and input-unsafe in the section Variance Safety of the C# Language Specification. I'm familiar with the concept of variance (both covariance and contravariance), which basically refers to the usage of one type in place of another type.

So what is really meant by output or input safety? And Are we talking about type-parameters in generic types here or any type (reference or value)?

Was it helpful?

Solution

This part of the spec -- you are referring to section 13.1.3.1 of the C# 4 specification, which perhaps you ought to have mentioned somewhere in your question -- is unfortunate, and I apologize. Mads and I meant well, but I've never been thrilled with how this part of the spec turned out.

We were attempting to come up with a more intuitive and easy-to-understand description of "covariantly valid", "contravariantly valid" and "invariantly valid" for the C# specification; the original draft specification was written with these terms, which people found confusing. The result was not actually much easier to understand, and it contained some errors.

My advice is: if you need to understand the precise rules for what makes a variant interface valid or invalid then you should read my notes on the subject which are here:

http://blogs.msdn.com/b/ericlippert/archive/2009/12/03/exact-rules-for-variance-validity.aspx

That is essentially an annotated transcription of the notes that I made while implementing the feature. These notes are much more detailed and hopefully more clear than the text that ended up in the spec.

You might also want to read the relevant section in the CLI specification; my notes were based directly on a thorough reading of it.

To actually answer your question: the idea behind "output unsafety" and "input unsafety" is essentially that if you have:

interface I<in T>
{
  T M();
}

Then T cannot be safely used in output positions. Suppose we allowed this; doing so violates type safety:

class C : I<Animal> 
{ public Animal M() { return new Giraffe(); } }
...
I<Animal> ia = new C<Animal>(); 
I<Tiger> it = ia; // Contravariant!
Tiger t = it.M(); // We just assigned a giraffe to a variable of type tiger.

That violates type safety, so we say that T is "output unsafe", and therefore this interface is not valid, because plainly T is used in an output position. Similarly for "input unsafe":

interface I<out T>
{
    void M(T t);
}

You could make an I<Giraffe> that takes a giraffe, convert it to I<Animal> and pass in a tiger to M, which is not safe. T is input-unsafe, and therefore this interface, which uses T in an input position, is not valid.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top