3

Is it considered good practice or bad practice to write an interface that exists solely to concentrate other interfaces?

interface InterfaceA : InterfaceB, InterfaceC {
}

In doing this, a concrete implementation only needs to implement InterfaceA, which seems like a good thing, but it doesn't add any value by extending, which seems wasteful.

Andras Zoltan
  • 41,961
  • 13
  • 104
  • 160
redman
  • 1,510
  • 17
  • 33
  • And why am I suddenly showing up as "user123432"? That is not my id on StackOverflow. – redman Oct 20 '10 at 12:40
  • Are [that](http://stackoverflow.com/users/123432/user123432) your questions? Anyhow, you can visit [meta.stackoverflow.com](http://meta.stackoverflow.com) to check for bugs. – Boldewyn Oct 20 '10 at 13:01
  • Turns out my display name in my profile was wiped out. Caught me by surprise, I haven't had that happen before. – redman Oct 20 '10 at 13:02

4 Answers4

2

I think it depends on if it makes sense in your domain. If it does, I would do it, then your program more accurately models your domain.

In addition, of course, you can now write code which requires/uses objects implementing InterfaceA i.e. all methods of both the super-interfaces; that wouldn't have been possible before.

Adrian Smith
  • 17,236
  • 11
  • 71
  • 93
  • Marked as the accepted answer because, while all answers were correct, looking at it from the domain angle clinched it. It does indeed make sense within my domain and the answer would have been obvious had I thought from that angle. – redman Oct 20 '10 at 13:17
1

If it makes sense, and you're going to be using all three interfaces independently, it can definitely be the appropriate design decision.

If it turns out that InterfaceB and IntefaceC won't ever be used, then just make InterfaceA...

Dave Markle
  • 95,573
  • 20
  • 147
  • 170
1

It is indeed useful for maintaining code readability, then you can use the concrete implementation of interface A where interface B or C are required.

dvhh
  • 4,724
  • 27
  • 33
1

I was going to ask this same question but decided to be really wary and do some extensive searching - to avoid duplication. Then I found this one - I've edited the title in the hope that it'll become more popular, because it should.

First, we should be aware that an empty interface such as this is also known as a marker interface - this other, unanswered, SO discusses concerns marker interfaces and Scott Wisniewsi's answer (currently top) is interesting when considering the rest of what I'm about to say.

In researching empty interfaces you'll typically stumble across the MSDN topic concerning Code Analysis warning CA1040 which specifically suggests that empty interfaces that don't implement at least two others should be avoided.

By that token - and of course not necessarily implying that Microsoft's coding guidelines are de-facto - in your example, that's exactly what you are doing (and what I want to do also in my current project) and therefore it would pass MS' own litmus test. As a result I'm happy to say 'yes, such an interface is perfectly reasonable'.

For justification, and I think a particularly good example of a reason why the 'at least two interfaces' switch is placed on this rule is similar to the situation I find myself in:

public interface IReadsAResource
{
  public byte[] Read(string id);
}

public interface IWritesAResource
{
  //returns the id
  public string Write(byte[] resource);
}

Given these two interfaces, I can now write a component that expressly states it only needs to read or write:

public class NeedsRead
{
  private readonly IReadsAResource Reader;
  public NeedsRead(IReadsAResource reader){ Reader = reader; }
}

public class NeedsWrite
{
  private readonly IWritesAResource Writer;
  public NeedsWrite(IWritesAResource writer){ Writer = writer; }
}

I will now typically choose to implement this interface on a single class ResourceReaderWriter, given that the data store for the resources will require dependencies that are shared by both method implementations, passing an instance of that when either interface is needed:

var needsRead = new NeedsRead(new ResourceReaderWriter(/* dependencies */));
var needsWrite = new NeedsWriter(new ResourceReaderWriter(/* dependencies */));

But then what if I have a class that needs to both read and write resources? With the interface ecosystem currently in place, I need two constructor parameters:

public class NeedsReadAndWrite{
  public NeedsReadAndWrite(IReadsAResource reader, IWritesAResource writer){
    /* reader/writer local variables elided */
  }
}

Not such a hardship, you might say, but it's causing two problems:

  • The implication is that we have two separate instances that are responsible for reading and writing resources; therefore our class cannot be sure that both are consistent with each other. Equally, it cannot be sure that state is managed correctly between the two.
  • As a caller, I can of course sidestep this by creating a single instance first, and passing it for both parameters. But that's taking away my ability to create the object in a one-liner and just seems weird.

Anybody who's stuck with me for this long will see where I'm going now :)

The elegant solution is to introduce an interface for a type that supports both reading and writing:

//denotes a component that can both read and write
public interface IReadsAndWritesAResource : IReadsAResource, IWritesAResource
{

}

With this interface, our problematic type can be re-written as

public class NeedsReadAndWrite{
  public NeedsReadAndWrite(IReadsAndWritesAResource readerWriter){
    /* local variable assignment elided */
  }
}

And both these problems are now side-stepped.

Equally it becomes simple to create a basic proxying type that implements this new interface by taking in instances of a reader and a writer and forwarding the read/write calls on to those.

I think this example demonstrates exactly why you would, or perhaps even should, use marker interfaces that pool together two or more others.

Community
  • 1
  • 1
Andras Zoltan
  • 41,961
  • 13
  • 104
  • 160
  • I would suggest that an empty interface which inherits exactly one other could be a good and useful thing (though underutilized). For example, I would have like to have seen a few derivatives if `IEnumerable`, some with added members and some without. For example, `IMultipassEnumerable` should have derived from `IEnumerable` and returned an `IMultipassEnumerator` with a `Reset()` method (which should not have been in `IEnumerator`). `IImmutableEnumerable` should have derived from `IMultipassEnumerable`, and... – supercat Mar 08 '12 at 16:14
  • ...not added any new members but instead add a promise that all enumerators returned by `GetEnumerator` would return the same set of `T` objects (note that the `T` objects themselves may or may not be immutable; the promise would be that the enumerator would always return the same set of them). Code which will store a reference to an `IEnumerable` for the purpose of storing the content could use `IImmutableEnumerable`. – supercat Mar 08 '12 at 16:19
  • Yes I can definitely see the potential there, and the argument for it. The problem with a truly empty interface that supposedly promises something like that, though, is that there is no way to enforce it. That a class implements that interface is no guarantee that it will play fair. But in a closed system that's not a problem I guess. – Andras Zoltan Mar 08 '12 at 17:04
  • Even in non-closed systems, interfaces have semantic expectations. For example an `IEqualityComparer` is supposed to be written such that for any pair of instances `X` and `Y`, calling `theComparer.Equals(X,Y)` should always yield the same value (meaning the comparison should only depend upon immutable aspects of `X` and `Y`). It is considered entirely reasonable and proper for collection classes to rely upon this behavior, even there is no way for a collection class to enforce it. – supercat Mar 08 '12 at 18:28
  • That is indeed, very true - ultimately I suppose a promise is a promise! – Andras Zoltan Mar 08 '12 at 18:59