Understanding C# Covariance And Contravariance (6) Typing issues

Understanding C# covariance and contravariance:

In each previous part, type implicit conversion is dicussed, which happen during the variances, like

  • function (method / delegate) conversion, as well as higher-order function conversion;
  • generic interface conversion;
  • array conversion.

Since C# 4.0 introduces new variance rules, which means in C# 4.0, types could be more convertible than C# 2.0 / 3.0, there could be potential typing issues for C# 4.0. If comparing some code between Visual Studio 2008 (C# 2.0 / 3.0) and Visual Studio 2010 Beta2 (C# 4.0), you can find that is true.

Delegate covariance / contravariance issues

Take a look at this covariance sample:

Func<Base> baseFunc = () => new Base();
Func<Derived> derivedFunc = () => new Derived();

// This always prints "True".
Console.WriteLine(derivedFunc is Func<Derived>);
// Covariance is supported by C# 4.0.
// This prints "False" in C# 2.0 / 3.0, prints "True" in C# 4.0.
Console.WriteLine(derivedFunc is Func<Base>);

And this contravariance sample:

Action<Base> baseAction = arg => { };
Action<Derived> derivedAction = arg => { };

// This always prints "True".
Console.WriteLine(baseAction is Action<Base>);
// Contravariance is supported by C# 4.0.
// This prints "False" in C# 2.0 / 3.0, prints "True" in C# 4.0.
Console.WriteLine(baseAction is Action<Derived>);

Yes, in C# 4.0, delegate types are more convertable.

Interface covariance / contravariance issues

This is the interface covariance on IEnumerator<out T>:

IEnumerator<Base> baseEnumerator = new BaseEnumerator();
IEnumerator<Derived> derivedEnumerator = new DerivedEnumerator();

// This always prints "True".
Console.WriteLine(derivedEnumerator is IEnumerator<Derived>);
// Covariance is supported by C# 4.0.
// This prints "False" in C# 2.0 / 3.0, prints "True" in C# 4.0.
Console.WriteLine(derivedEnumerator is IEnumerator<Base>);

It looks acceptable.

Then this is covariance on IEnumerable<out T>:

IEnumerable<Base> bases = new Base[0];
IEnumerable<Derived> deriveds = new Derived[0];

// This always prints "True".
Console.WriteLine(deriveds is IEnumerable<Derived>);
// Covariance is supported by C# 4.0.
// This prints "True" in C# 2.0 / 3.0 / 4.0.
Console.WriteLine(deriveds is IEnumerable<Base>);

Looks like a big mess.

To try interface contravariance, IComparable<in T> can be used as an example:

internal class Base : IComparable<Base>
{
    public int CompareTo(Base other)
    {
        throw new NotImplementedException();
    }
}

internal class Derived : Base
{
}

Then:

IComparable<Base> baseComparable = new Base();
// This cannot compile in C# 2.0 / 3.0,
// because Derived does not implement IComparable<Derived>.
IComparable<Derived> derivedComparable = new Derived(); // This always prints "True". Console.WriteLine(baseComparable is IComparable<Base>); // Contravariance is supported by C# 4.0. // This prints "False" in C# 2.0 / 3.0, prints "True" in C# 4.0. Console.WriteLine(baseComparable is IComparable<Derived>);

The interface variances are also confusing.

Conclusion

C# 4.0 introduces new variance rules, so in C# 4.0, types becomes more convertible than C# 2.0 / 3.0. And this makes the same code work differently between C# 2.0 / 3.0 and C# 4.0.

2 Comments

  • The broken menu's link here at the
    "Understanding C# covariance and contravariance (7) CLR"
    The
    http://www.cnblogs.com/dixin/archive/2009/09/08/understanding-csharp-covariance-and-contravariance-7-clr.html
    should be the
    http://weblogs.asp.net/dixin/archive/2009/09/08/understanding-csharp-covariance-and-contravariance-7-clr.aspx
    address.

  • All the links at the menu on this page are broken.

    Understanding C# covariance and contravariance (1) Delegates
    Understanding C# covariance and contravariance (2) Interfaces
    Understanding C# covariance and contravariance (3) Samples
    Understanding C# covariance and contravariance (4) Arrays
    Understanding C# covariance and contravariance (5) Higher-order functions
    Understanding C# covariance and contravariance (6) Typing issues

    Understanding C# covariance and contravariance (8) Void

Comments have been disabled for this content.