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).
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.interface {}
marker interface
. See other posts regarding them, e.g. softwareengineering.stackexchange.com/questions/316824/…