Generics Covariance is illegal

Most of modern object oriented languages now support generics since C++ introduced it. More and more programmers found its useful and flexible to design advanced concepts as well as lots of useful libraries came out after famous C++ STL.
Honestly, I haven't had deep knowledge or experience on it but started using it since all the languages I'm handling have it as core role of features.
Recently, I've deployed lots of abstract types to design multiple modules completely decoupled to each other and needed to introduce generic list of such abstract type since C# support list using generics like following.

List<IDeviceDetail> getDeviceDetailList()
{
   ...
}

In fact, we have LINQ statements inside of the method which returns a list of generics.

var details = from p in context.DeviceDetail
                          select p;

where details can return a type of IList<DeviceDetail> when we call ToList().
I finished up this method like this without any doubting

List<IDeviceDetail> getDeviceDetailList()
{
  var details = from p in context.DeviceDetail
                          select p;
  return details.ToList(); 
}

and… it caused compile error.

covariantgenericserror.jpg

Ooops! What's wrong with it? Must be a casting problem? But casting doesn't even help this problem.
I asked couple of my friends, searched Google, IBM developerworks(1) and finally concluded this is not allowed in any language!

I'll explain in short for those who don't want to navigate to different page to read it.
By allowing Covariance Generics, we can allowing invalid assignment in the future.
For example, assume we have BabyPatient and AdultPatient which implement IPatient (or inherit PatientBase)
Then following thing can happen by allowing Covariance Generics

interface IPhysician {...}
class Pediatrician: IPhysician {...}
class Surgeon: IPhysician {...}
...
IList<IPhysician> pediatricians=new IList<Pediatrician>(); // 1
IList<IPhysician> physicians=pediatricians; // 2.. which is illegal
physicians.Add(new  Surgeon()); // 3

Since physicians is type of IList<IPhysician>, it's perfectly legal to append a Surgeon to its list. This breaks type safety because physicians actually refers to pediatricians which is list of Pediatrician.

The only workaround to this is to reinitialize new list completely and there's little useful utility(3) to do this.

public class EnumerableGeneric<TClass, TInterface> : IEnumerable<TInterface>
    where TClass : TInterface
{
    private IList<TClass> list;

    public EnumerableGeneric(IList<TClass> list)
    {
        this.list = list;
    }

    public IEnumerator<TInterface> GetEnumerator()
    {
        foreach (TClass item in list)
            yield return item;
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }
}

using this I could complete my method like following

List<IDeviceDetail> getDeviceDetailList()
{
  var details = from p in context.DeviceDetail
                          select p;
  return EnumerableGeneric<DeviceDetail, IDeviceDetail>(details.ToList()).ToList(); 
}

It's not a perfect solution since we're using two different copies of objects, now.
Maybe it's a design problem rather than a language feature.
Keep in mind that Covriance Generics is not allowed.

Bibliography
1. B. Goetz ; Java theory and practice - Generics gotchas ; IBM developerWorks ; 2005.
2. E. Gunnerson ; Generics and Wildcards ;MSDN blog ; 2005.
3. S. Delmarco ; Covariant Generic (EnumerableGeneric) ; Fotia ; 2007.
Add a New Comment
or Sign in as Wikidot user
(will not be published)
- +
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License