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 methodsSo 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.
What is the benefit of using an interface that doesn't enforce anything (marker interface)?
object oriented design;interfaces;generics
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).