Tuesday, April 28, 2009

Interface “inheritance” in C#

Explanation of how interface inheritance is implemented in .NET, and how to properly use it in C#.

I have had a little debate not long ago about pros and cons of interface inheritance in .NET C# language. It may be worth restating the main points of the discussion.

Definition from C# language specification: (http://msdn.microsoft.com/en-us/library/aa664578(VS.71).aspx)

An interface can inherit from zero or more interfaces, which are called the explicit base interfaces of the interface

Example: per definition above IComboBox inherits ITextBox, IListBox, and indirectly IControl interfaces. The official definition notwithstanding, note that you can also say the IComboBox implements the same interfaces without violating the meaning and implications of the resulting relationship.

interface IControl
{
void Paint();
}
interface ITextBox: IControl
{
void SetText(string text);
}
interface IListBox: IControl
{
void SetItems(string[] items);
}
interface IComboBox: ITextBox, IListBox {}




Next is interface implementation. A class can implement an interface. Unfortunately, in C# unlike VB and Java, the syntax for inheritance and implementation is the same, i.e. the syntax simply uses “:” operator. Result – lots of confusion.








interface IMyInterface {}
class MyClass : IMyInterface {}



The difference becomes a little clearer when you consider this example:







public interface IMyBaseInterface
{
void DoA();
}
public interface IMyDerivedInterface : IMyBaseInterface
{
void DoB();
}
public class MyClass : IMyDerivedInterface
{
void DoA();
void DoB();
}






The result of MyClass explicitly implementing IMyDerivedInterface is that it implicitly got saddled with a requirement to also explicitly implement IMyBaseInterface.







“So. What exactly is the problem?” After all, Microsoft is using interface inheritance in .NET framework for ICollection : IEnumerable definition and the like. Here are my objections to the interface inheritance practice on a broad scale:




  1. Interfaces are contracts. Implicit contracts are like a programming fine print. An interface is a pure definition and always requires a class to implement the declared contract behavior. Per the example above, MyClass indirectly realizes the contract IMyBaseInterface behavior, but has to explicitly implement it nonetheless. A better practice is simply for IMyDerivedInterface not to inherit IMyBaseInterface and for MyClass to explicitly implement both IMyDerivedInterface and IMyBaseInterface interfaces. The result is the same without the “fine print” contract. This way, another class wanting to implement only IMyDerivedInterface would not be forced into implementing DoA() of IMyBaseInterface interface.







    public interface IMyBaseInterface
    {
    void DoA();
    }
    public interface IMyDerivedInterface
    {
    void DoB();
    }
    public class MyClass : IMyDerivedInterface, IMyBaseInterface
    {
    void DoA();
    void DoB();
    }











  2. Interface inheritance practice contradicts polymorphism through interface implementation that emphasizes using a single interface behavior to interact with objects of different types that implement it. From the previous example, interface IMyBaseInterface is always implicitly dragged into every implementation for every type that is simply trying to implement only IMyDerivedInterface methods. This is no longer a single behavior for a single interface.










  3. Interface inheritance practice leads to unnecessary code duplication instead of code reuse. Even in a case of ICollection : IEnumerable interface definition, I wonder if such tacking on of IEnumerable contract was necessary. In a perfect world, one would be better off inheriting from an abstract class or a class that has IEnumerable rudimentary implementation once: i.e. the showcase of reuse with inheritance. I am not completely opposed to interface inheritance. Even ICollection : IEnumerable may have additional valid considerations I am missing. However, on a broad scale, interface inheritance adds more contract “fine print” and forces potentially unnecessary implementation and code duplication.










  4. Interface is a contractual constraint. It has no behavior of its own, and thus, produces no value of its own. Interface inheritance makes the contractual constraint on an implementing class even more convoluted, but still produces no value of its own: all interfaces in the inheritance tree still need a class to produce any value.










  5. Finally, in spite of C# interface inheritance definition and terminology in the C# language spec, .NET framework compiles all interface “inheritance” definitions as interface implementation. For example, the compiled ICollection : IEnumerable interface definition is interpreted as ICollection implements IEnumerable, not inherits. That is true for generics too. You can the example below for yourself:
















1









Upon the breakpoint, check ic variable, and note the BaseType value:









2









Now check the result of ic.GetInterfaces():3









This is a long way to say: interfaces are to be implemented, not inherited from. Do not use interface inheritance unless it is unavoidable, and by “unavoidable” I mean “almost never”.









13 comments:

  1. Interface is a contract. A derived interface is a combined contract. Consider a class that implements derived interface. You may argue, that it may not be clear in terms of readability or development process, but that what it is, if you choose to implement derived interface you are obliged to honor its combined contract. Do not quite see the problem here.

    ReplyDelete
  2. The problem is mainly in maintaining, extending, or reusing code written with this style. Inheriting interfaces adds NO VALUE, but forces to expend time and effort (i.e. $) to explicitly implement whatever interfaces are in the inheritance hierarchy. Class inheritance - good, interface inheritance - usually useless or just bad.

    ReplyDelete
  3. Consider two developer resources. One designes module interface. In design of the interface he choses to use hierarchy, because some of the interfaces have content and behaviour that are better expressed using base interface. When done he has a hierarchy structure. A derived interface represents a combined contract according to its hierarchy. This is how it was intended in the design. Any class, that chooses to implement this derived interface, must honor interface designer intentions and implement all the interfaces along hierarchy - provide implementation for the combine contract.
    Implementor may choose to use implementing class hierarchy, and implement required functions in classes along that hierarchy. On other hand he may choose stand-alone class and in this case this class must provide all required implementations.
    The point is, as it seems to me, that interface designer designed a contract required. If in this design there are members, that should not really be there, then the problem is with interface design, not with the approach.

    ReplyDelete
  4. You are missing my point. "In design of the interface he choses to use hierarchy" - right here, this is a poor choice. Choosing to design a hierarchy of interfaces in C# or VB .NET provides no advantages. Instead, it makes contracts more complex, gives no benefits of reuse, and forces people into implementing all hierarchy of interfaces, rather than the single one they may have needed

    ReplyDelete
  5. hello Oleg Semenov,

    I understood your point of view, but I can't be 100% agree with you. As .NET framework developer (which in this case is Microsoft), they couldn't limit our design choices: it's up to us to understand and use as efficient as possible the interface inheritance.
    Also, please study the IList interface, to see the tree. It's simple and concise.

    Greetings

    ReplyDelete
  6. Stefan,
    I am not quite sure what you disagree with. My recommendation to implement interfaces rather than inherit them is simple common sense. The design choice for an interface cannot get any more simple and efficient than to implement it.
    I do not know why MS developers chose to use interface inheritance in IList and other cases. There is more to designing a framework than to designing a regular app, and my recommendation is more about the design style and practices than the rule on par with the law of gravity. Even so, MS framework and CLR designers made the design choice for the C# compiler and CLR to still interpret and implement IList (or ICollection in my example) as interface implementation 'under the hood'.

    ReplyDelete
  7. Oleg,

    I stumbled on your argument against using interfaces & I cannot agree more with the frustration in finding some real benefit with having them at our disposal.

    However, I actually found a great example of using interfaces & I hope you'll find this example of some interest in a real-world web development scenario:

    Consider a situation where you want to build a login form. You would notice that you have two basic UI class containers in which to implement your form controls & logic:

    1) System.Web.UI.Page (PAGE)
    2) System.Web.UI.UserControl (CTRL)

    Suppose you quickly implement the form within a PAGE code-behind (or separate base page) & the actual code looks something like this:

    public class LoginPage: Page{
    protected void MyProprietaryFormLogic(){ /* something hard to understand but it just works & has been tested to work */ }
    public void Page_Load( object sender, Event e){
    if( !IsPostBack){ //The IsPostBack property exists in both Page & UserControl, but does not exist in Control or Template!
    MyProprietaryFormLogic();
    }
    }
    }

    Consequently, all the intense form logic above that you spent some good hours on gets immediately tied down to that page's code-behind. But you've tested the form. It all works & the project is done & you call it a day. Or is it?

    Here is the problem. Suppose a fellow co-developer wants to reuse your complex form-logic within a CTRL (as opposed to another PAGE container) for a satellite website. Your co-developer would be quite frustrated that your code is not readily reusable as it needs to be copied-&-pasted (for quick development) to get the project done. Copying the code will pollute the codebase with duplicate code-logic & refactoring/touching your code in anyway would force your co-developer to retest the PAGE that you completed for a different project that only you have full knowledge on how to test. Basically, if your co-developer refactors your code, there's always a chance that the login form your developed & tested might break.

    So how do you centralize that form logic for a Control object taken from a code-behind of a Page object? Consider the following:

    public interface ILogin{
    public bool IsPostback{ get; } //change 'b' to lowercase so it does not conflict w/ pre-existing IsPostBack
    public LoginController LC{ get; set;} //in case you want to use FindControl, etc.
    }

    public class LoginController{ //this controller can now be instantiated within a Page or UserControl
    public LoginController( Control objCtrl){ m_ctrlLoginView=objCtrl;}
    protected Control m_ctrlLoginView = null;

    public bool IsPostBack{ get{ return ((ILogin)m_ctrlLoginView).IsPostback;}} //cast as ILogin, IsPostBack is now available

    protected void MyProprietaryFormLogic(){ /* something hard to understand but it just works & has been tested to work */ }
    public void Page_Load( object sender, Event e){
    if( !IsPostBack){ //calling the abstracted IsPostBack call, doesn't matter if it's a Page or Control .. as long as it supports the ILogin interface
    MyProprietaryFormLogic();
    }
    }

    public void Page_Load( object sender, Event e){ LC.Page_Load( sender, e);} // let controller handle logic

    }

    //Now Login page becomes...

    public class LoginPage: Page, ILogin{ //Page version
    protected LoginController m_objController = null;
    public LoginController LC{ get{ return m_objController;} set{ m_objController=value;}}
    public LoginPage(){ LC = new LoginController( this); }
    public bool IsPostback{ get{ return IsPostBack;}}
    public void Page_Load( object sender, Event e){ LC.Page_Load( sender, e);} // let controller handle logic
    }

    //& most importantly, your co-developer can quickly reuse your controller logic by creating a complementary proxy class for the UserControl version (change out Page -> UserControl)
    public class LoginControl: UserControl, ILogin{ //UserControl version
    public LoginPage(){ LC = new LoginController( this); }
    ...
    }

    ReplyDelete
  8. Funny - Nelson at 3DBuzz.com would say using interfaces is far, far better than inheritance.

    ReplyDelete
  9. I agree with you to a point; however, when used correctly, what it does provide is convenience to consumers of the interface. What the designer of IList is saying by "deriving" IList from ICollection, for example, is that a class that is a list is also ALWAYS a collection: that is the key test of whether it is the right thing to do. If a list could ever not be a collection, you're right in that you'd be forcing list implementers to implement collection functionality needlessly.

    If IList had gained its collection semantics by mirroring the properties and methods of ICollection explicitly as opposed to inheriting from ICollection, what that would lose is the ability to pass an instance of a class that implements IList to something which is expecting an ICollection, without the class designer knowing that this subset relationship exists and remembering to include both interfaces in the class definition. Furthermore, where a consumer has obtained an IList reference, it could not be treated as an ICollection reference without casting.

    Consider the following example:

    class MyList : IList, ICollection
    {
    ...
    }.

    class MyClass
    {
    IList GetList()
    {
    return new MyList();
    }
    }

    class MyOtherClass
    {
    private MyClass _member = new MyClass();

    public MyOtherClass()
    {
    // without interface inheritance, this would not compile without
    // a cast even though a MyList implements ICollection
    ClassThatHandlesCollections.DoSomethingWithCollection(_member.GetList());
    }
    }

    So interface inheritance allows us to declare to implementers, consumers and the compiler that anything that is an IList can be treated as an ICollection.

    ReplyDelete
    Replies
    1. I would accept your reasoning for IList vs ICollection. Scenarios you described I usually see in writing or consuming framework classes and interfaces. Hence, I made a caveat of "almost never" use interface inheritance. On a large scale, when you see interface inheritance, and it is not part of some framework type of classes, it is more often then not an error, i.e. somebody did not know what he was doing.

      Delete
    2. Thanks for your response and clarification. Apologies for the duplicate posts, the website suggested they'd failed.

      Delete
  10. I'm not sure I agree that interface inheritance is poor. If I have an IServersideActor and an IActor why should my IServersideActor not implement the IActor interface? What is the point of not doing so? Instead of specifying a method take an IServersideActor I'd instead have to have it take T where T : IServersideActor, IActor. That seems pointless if all IServersideActors are IActors anyway.

    ReplyDelete
    Replies
    1. Interface is not a class it is a contract w/o implementation. If "all IServersideActors are IActors anyway", then why do you have 2 contracts that define the same behavior? If you end up passing a derived interface into a method only to have an "if" or a "switch" to distinguish between them, then I would question if the contracts and classes need to be refactored.

      Delete