Curioddities: part 1 (Kit George)

Curioddities: part 1 (Kit George)

  • Comments 9

Well, I thought I would start a series on interesting things in the framework, and see what people thought about things I find interesting or odd. I'd also love to know what other things you find odd ir interesting that don't happen to come up.

For this week, I thought I'd give you a bit of code, and simply ask: do you expect this to compile? If so, why? And if not, why not? Of course, you can go and simply try it out (and fee free to do so, obviously, as library code), but let me know what your intitial expectation was, and whether seeing the actual result changed your mind.

interface ITest {

      void SomeMethod();

} 

class Test1 {

      public virtual void SomeMethod() {}

}

class Test2 : Test1, ITest {}

  • This does not compile, since implementing an interface in a class requires all of the members to be declared at that level explicitly.
    Moreover, if you implement ITest in Test1, you would still get a compile-time error saying that you have not implemented ITest.SomeMethod in Test2.

    I would expect this to not compile anyway. If I want it to use the base class's method, I would use the following syntax:

    class Test2 : Test1, ITest
    {
    _ _ ITest.SomeMethod() { base.SomeMethod(); }
    }

    This is good behavior, since this way we can differentiate between implicitly implementing an interface and explicitly implementing it.
  • I did not try it, but yes it will compile. And you can create 2 methods in "Test2" called "SomeMethod" and "ITest.SomeMethod" and have them do different things. Which one gets called depends on if the caller is using the ITest interface or just calling your object directly.
  • I think it will compile. I think Test1.SomeMethod would be considered as the implementation for ITest.SomeMethod(). Test1.SomeMethod could be overridden in Test2 to provide another implementation.
  • I ran into a variant of this a few days ago. (Comments in LadyBug FDBK13067. I refer to partial and full interface implementation, allow it is my terminology.)

    I was surprised that this actually would compile. In my opinion, when a type is declared to implement an interface such as in Test2, I think that it should be required to explicitly define the methods for that interface _even if it means hiding a base class definition_. Is anything gained from saying that Test2 implements ITest? What was the rational for allowing this type of behavior?

    I was glad to notice that an instance of Test1 returns false when tested against "... is ITest" while the same test for Test2 returns true.
  • I didn't try it yet but let me add some names and see if it makes sense

    interface ISerializable {
    void Save();
    }

    class GenericDoc {
    public virtual void Save() {}
    }

    class TextDoc : GenericDoc, ISerializable {}

    TextDoc does know how to save itself, using GenericDoc.Save(). It seems to make sense that TextDoc can be accessed from code that expects objects to know how to save themselves.

    (note: I just tried it after writing the above and my initial expectation didn't change :)
  • I do think it ought to compile, and it does.
  • Well thanks all for the responses. Myself, I was very suprised to find that this compiled. The satisfaction of the ITest contract is something which I think either the current consumer (Test2) has to ensure they have explicitly performed, or, a parent of Test2 can be demonstrated to have performed.

    I don't see that in the above sample. Test1 happens to have a method called SomeMethod, but in no way does that meet any contractual obligations of ITest (beyond the name of the API). Test2 is allowing that method to satisfy it's own contract, without any knowledge about whether it actually does so. I do like Eusebio's demonstration above, that when we start talking about a real method name, we can see that Save is often going to be similar. But interfaces are also meant to define an expectation upon implementors, which in this scenario, is probably not being addressed.

    I guess what concerns me at the end of the day here, is that an error could have 'slipped through'. The person designing IText might not have noticed that the ITest contract was satisfied, and therefore, doesn't know if SomeMethod satisfies the contract appropriately. I would have thought it was more interesting to require the designer explicitly make that decision in this case, rather than implicitly.

    Thanks again for the input! I'll get another curriodity up shortly.

  • Isn't the only test of adherence to an interface method contract the method signature? How else to model the interface "expectation"? If the implementation's method signature matches, and is not overridden explicitly, then that should be good enough for the compiler.

    This capability allows us to use aggregation to provide interface implmentation without the tedious work of explicitly mapping the interface methods to the base class equivalents.

    Personally, I like how the VS.Net IDE creates stubs for each interface method in my class; which reduces the chance of making the type of error you suggest.
  • Another interesting note is that if you use the Class View in the IDE and use the "Implement Interface" command on ITest for the Test2 class, it will add code that will not compile. You will manually have to add the override keyword in order to get it to work (which makes sense of course).
Page 1 of 1 (9 items)