You've got to be kidding me!

In the spirit of the post on Covariant Return Types, and "Death by a thousand cuts", i thought I'd mention yet another intensely aggravating part of .Net development.  This one isn't about C# per se, but C# is affected by it.

I'm going to use a real world example here.

In the .Net FX v1.0 and v1.1 we had the type which i'm sure you all know and love:

public interface IEnumerator {

     object Current { get; }

     bool MoveNext();

}

 

Now, we come along to .Net FX v2.0 with it's introduction of the generic collections.  Ok, so we know that we definitely want an IEnumerator<T>, but now where do we fit it into the whole hierarchy.  Well, after giving it a moment of though we can say to ourselves: "well, IEnumerator allows you to enumerate a list of objects... a-ha!" and you come up with this new hierarchy:

public interface IEnumerator<T> {

     T Current { get; }

     bool MoveNext();

}

public interface IEnumerator : IEnumerator<object> {

}

 

Simple, clean, elegant.  IEnumerator cleanly fits into the new generic hierarchy as an enumerator of objects, and so all your old IEnumerator code will work with new code that expects generics.  There would seem to be no issue of backwards compatability because the IEnumerator interface is losing not methods.  Rather, the methods are still there just in a superinterface.  So if call .Current on an IEnumerator, you will get a good old object back, same as you used to.

But can we do this? No.  Why not?  Well, because one of the things we allow an implementor of an interface to do is "Explicit interface implementation".  This handly little feature which allows you to implement two different interfaces with the same members now turns out to the bane of anyone wanting to clean up their interfaces in a way that would normally be safe in many other languages.  Why is it now unsafe?  Well, imagine the following code:

class UserClass : IEnumerator {

     object IEnumerator.Current { get { ... } }

}

 

Once we move IEnumerator.Current into IEnumerator<T>.Current we suddenly break this code.  IEnumerator doesn't have a .Current and so you can't explicitly implement it that way.  instead you need to do:

class UserClass : IEnumerator {

     object IEnumerator<object>.Current { get { ... } }

}

 

And it's pretty much guaranteed that there are thousands (if not much much more) of cases where users have done exactly this.  So making this change ensures that we're destroying a ton of code through backwards compatibilty problems.

I've never been a fan of explicit interface implementation, and here's one more reason why.  When i did java development it just never was the case that this would have been helpful.  And, while i can acknowledge that it might turn up, it doesn't seem like the pains it causes are worth it.  I also think that much of it is due to the old style MS Com development where you have one object implementing like 50 interfaces.  In java and .Net you just dont see that and this really was overkill considering all the problems it's introduced.

Sigh...