(Disclaimer: I’m 99% sure I’ve heard someone smarter than me talking about this before, so it’s definitely not original. I thought it worth pursuing though.)
One of the things I love about Java and C# over C/C++ is the lack of .h files. Getting everything in the right place, only doing the right things in the right files, and coping with bits being included twice etc is a complete pain, particularly if you only do it every so often rather than it being part of your everyday life.
Unfortunately, as I’ve become more interface-based, I’ve often found myself doing effectively the same thing. Java and C# make life a lot easier than C in this respect, of course, but it still means duplicating the method signatures etc. Often there’s only one implementation of the interface – or at least one initial implementation – but separating it out as an interface gives a warm fuzzy feeling and makes stubbing/mocking easier for testing.
So, the basic idea here is to extract an interface from a class definition. In the most basic form:
class interface Sample { public void ThisIsPartOfTheInterface() { } public void SoIsThis() { } protected void NotIncluded() { } private void AlsoNotIncluded() { } } |
So the interface Sample
just has ThisIsPartOfTheInterface
and SoIsThis
even though the class Sample
has the extra methods.
Now, I can see a lot of cases where you would only want part of the public API of the class to contribute to the interface – particularly if you’ve got properties etc which are meant to be used from an Inversion of Control framework. This could either be done with cunning keyword use, or (to make fewer syntax changes) a new attribute could be introduced which could decorate each member you wanted to exclude (or possibly include, if you could make the default “exclude” with a class-level attribute).
So far, so good – but now we’ve got two types with the same name. What happens when the compiler runs across one of the types? Well, here’s the list of uses I can think of, and what they should do:
- Variable declaration: Use the interface
- Construction: Sse the class
- Array declaration/construction: Use the interface (I think)
typeof
: Tricky. Not sure. (Note that in Java, we could useSample.class
andSample.interface
to differentiate.)- Type derivation: Not sure. Possibly make it explicit: “
DerivedSample : class Sample
” or “DerivedSample : interface Sample
” - Generics: I think this would depend on the earlier “not sure” answers, and would almost certainly be complicated
As an example, the line of code “Sample x = new Sample();
” would declare a variable x
of the interface type, but create an instance of the concrete class to be its initial value.
So, it’s not exactly straightforward. It would also violate .NET naming conventions. Would it be worth it, over just using an “Extract Interface” refactoring? My gut feeling is that there’s something genuinely useful in here, but the complications do seem to overwhelm the advantages.
Perhaps the answer is not to try to have two types with the same name (which is where the complications arise) but to be able to explicitly say “I’m declaring interface ISample
and implementing it in Sample
” both within the same file. At that point it may be unintuitive to get to the declaration of ISample
, and seeing just the members of it isn’t straightforward either.
Is this a case where repeating yourself is fundamentally necessary, or is there yet another way of getting round things that I’m missing?