3

The codebase I'm working on makes a lot of use of interfaces that don't actually enforce anything. They're in place more to make sure that a type 'is a' something. For example:

   public class MyBatchTask : Task, ITask<MyTaskType>
   {
       ...

   public interface ITask<TId> : ITask where TId : ITaskId
   {}

   public interface ITaskId {}

   public abstract class Task : ITask
   {
     .... base methods

So here, we're ensuring that 'MyBatchTask' 'is an' ITask, and that the 'MyTaskType' that we declare in the generic parameter 'is an' ITaskId', however these interfaces themselves don't actually enforce anything specific.

So, OK this is 'marking' certain types as having a particular semantic meaning (or being part of a recognised structure/pattern within the code), but how does that really help when the interface doesn't enforce any contract? It makes the code more abstract and more difficult to comprehend, so why use of this type of pattern at all? In practice, none of the interfaces have been extended over time to actually enforce any contract.

  • 2
    The serialization interface has no methods or fields and serves only to identify the semantics of being serializable. from the Official Java API doc page. I guess that could be also a use for interfaces without methods. – Laiv Jun 14 '17 at 4:39
  • 1
    You are right: It doesn't help you and it is superfluous. If you want to mark a class to have certain semantic I would suggest using simple Attributes. See this as a possible solution to your problem. – ckruczek Jun 14 '17 at 4:47
  • 1
    Or @Annotations – Laiv Jun 14 '17 at 5:25
  • Notice that the Go language has empty interfaces interface {} – Basile Starynkevitch Jun 14 '17 at 5:37
  • 1
    It's also called marker interface. See other posts regarding them, e.g. softwareengineering.stackexchange.com/questions/316824/… – Bernhard Hiller Jun 14 '17 at 8:18
4

This pattern can be used to good effect, but this doesn't look like an example. A good example would be to communicate semantic constraints/guarantees that don't otherwise change the API. For example, you could have an interface that represents a kind of operation, and an a sub-interface that indicates that the operation is idempotent. Then then returning an IIdempotentOperation indicates (intended) guarantees to the consumer, and receiving an IIdempotentOperation indicates additional constraints to the user.

But you have to have something to talk about. If the interface doesn't have (directly or indirectly) any methods, then either it's saying something about the methods on all objects, e.g. Equals, or it is saying that the object is one of a fixed, known set of classes for the purposes of type-casing via instanceof or similar. Maybe that is the idea, but then that's pretty ugly. If it isn't referencing a situation like either of the above, then there is absolutely no reason for the parameters to not be completely parametric, and it says nothing to implement such an interface.

I should clarify that it's ITaskId that seems completely useless to me. I can see what ITask<> is trying to accomplish. More context would be needed to tell if those interfaces are adding value. Excepting the scenarios I described above, there's literally no difference between class Foo and class Foo : ITaskId. Similarly, having a parameter of a method of type ITaskId is no different from having a parameter of type Object (or, preferably, abstracting it into a generic type parameter). There's simply no semantic constraint that's even informally expressible because there are no methods to constrain. Again, unless it's informally indicating a constraint on a method like Equals or ToString, there's simply no behavior for a constraint to constrain. I would even say that it is not just unnecessary to have the ITaskId constraint e.g. on TId, but it's actually a mistake. You can always constrain the TId type parameter in any particular use if necessary, but it may be useful to allow TId to be types that do not implement ITaskId, such as String, even if only during an intermediate calculation. The Haskell community has run into the issues of unnecessary constraints limiting flexibility in painful ways with the most notable example being the Complex type which used to be constrained but now is not (and in fact the language feature allowing constraints in such positions has been removed as they were always unnecessary).

  • Thanks and +1. Could you please expand Derek, on what you mean by 'there is absolutely no reason for the parameters to not be completely parametric' - thanks! – Chris Halcrow Jun 14 '17 at 5:23
  • Interfaces exist only as a workaround for the failure to provide multiple class inheritance in a language. They serve no other purpose. – Frank Hileman Jun 14 '17 at 22:56
  • 1
    @FrankHileman Whether that's true or not, it is completely irrelevant to the point. If instead of interfaces, ITaskId was a abstract class that was multiply inherited, everything I said would be just as true. – Derek Elkins Jun 14 '17 at 23:00
  • @DerekElkins yes, I agree with you. But others seem to believe interfaces are more than specialized base classes. – Frank Hileman Jun 14 '17 at 23:04
  • 1
    @FrankHileman Well, they're not. Just one example to prove that wrong: In C#, structs can not inherit from classes, but they can implement interfaces. CS also wouldn't agree with you that not providing multiple inheritance is a "failure". That's just like, your opinion, man. – R. Schmitz Oct 29 '18 at 14:01
-7

There is no benefit, except to appeal to other developers who believe there is a benefit. You will read lots about how interfaces are not the same as pure abstract base classes, but in the end, the only purpose for interfaces is to provide multiple inheritance. That is, in those languages that provide interfaces, multiple inheritance of classes is not implemented, and interfaces provide a work-around for this flaw.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.