24

Should a class know about its subclasses? Should a class do something that is specific for a given subclass for instance?

My instincts tells me that is a bad design, it seems like an anti-pattern of some sort.

  • 6
    Usually no, but in special cases it's useful. – CodesInChaos Nov 26 '13 at 15:20
  • It is an anti-pattern, a well known one called: "Liskov Substitution Principle" or sometimes just LSP, read about it at en.wikipedia.org/wiki/Liskov_substitution_principle – Jimmy Hoffa Nov 26 '13 at 16:21
  • 5
    @JimmyHoffa - "Liskov Substitution Principle" is not the name of an anti-pattern. An anti-pattern may violate LSP, but it's not even certain that this would be true here. It's possible that, even if a type knows it's subtypes, that the subtypes can still be substituted for their parent with contravariance and covariance. – Matthew Flynn Nov 26 '13 at 18:46
  • 4
    @MatthewFlynn Perhaps I'm using LSP a little loosely but in my definition it's not the fact that they all fulfill the requirements of eachother that complies with LSP, it's a requirement that they have a decoupling such that not only do they agree with eachother but you could implement another subclass that doesn't violate LSP. If the hierarchy is self-aware then an external implementation couldn't possibly meet LSP without altering the base class. Perhaps that's not strictly LSP but it's mighty close. and yes I should have said LSP violation is the anti-pattern – Jimmy Hoffa Nov 26 '13 at 18:54
  • 2
    The few times I have encountered this, I refactored that knowledge into a method which could be overridden in a subclass (either forced by making it abstract or pure virtual, or providing a sensible default implementation that could be overridden). – user22815 Nov 28 '13 at 7:27
32

The answer implied by the concept of classes is "no".

Either whatever action, data or relation you're handling is part of all subclasses - then it should be handled in the superclass without checking the actual type. Or it applies only to some subclasses - then you'd have to perform run-time type checks to do the right thing, the superclass would have to be changed whenever someone else inherits from it (or it might silently do the wrong thing), changes in the derived classes can break the unchanged superclass, etc.

In short, you get a number of bad consequences which are usually bad enough to reject such solutions out of hand. If several of your subclasses do the same thing and you want to avoid code duplication (practically always a good thing), a better solution is to introduce a mid-level class from which all those subclasses can inherit the code.

  • 4
    One exception to this rule: The documentation of the class should list its subclasses local to its own library. – Kieveli Nov 26 '13 at 13:00
  • 3
    @Kieveli ... as long as that documentation is kept up to date. – mouviciel Nov 26 '13 at 13:18
  • 14
    Any usable documentation tool should be able to draw inheritance trees ... – johannes Nov 26 '13 at 13:35
  • 13
    I don't think it is an exception. The class still doesn't know anything. The documentation knows. – Honza Brabec Nov 26 '13 at 16:09
  • 4
    @Kieveli uhh I completely disagree. – Jimmy Hoffa Nov 26 '13 at 16:47
16

Not only should it not know, it simply can't! Usually, a class can be extended anytime, anywhere. It can be extended by classes that didn't even exist when it was written.

Some languages allow extending classes to be controlled by the superclass. In Scala, a class can be marked as sealed, which means that it can only by extended by other classes within the same compilation unit (source file). However, unless those subclasses are also sealed or final, the subclasses can then be further extended by other classes.

In Scala, this is used to model closed algebraic data types, so the canonical Haskell List type:

data List a = Nil | Cons a (List a)

can be modeled in Scala like this:

sealed trait List[+A]

case object Nil extends List[Nothing]

final case class Cons[+A] extends List[A]

And you can guarantee that only those two sub-"classes" exist because List is sealed and thus cannot be extended outside of the file, Cons is final and thus cannot be extended at all and Nil is an object which cannot be extended anyway.

But this is a specific use case (modeling algebraic data types via inheritance) and even in this case, the superclass doesn't actually know about its subclasses. It's more a guarantee to the user of the List type that if he does a case discrimination of Nil and Cons, there won't be any other alternative popping up behind his back.

  • What works in many languages is adding some form of abstract internal member. – CodesInChaos Nov 29 '13 at 11:42
4

The simple answer is No.

It makes code brittle and voilates two basic principles of object oriented programming.

  • Liskov Substitution principle
  • Open Close principle
1

Yes, sometimes. For example, when there is a limited number of subclasses exist. A visitor pattern is an illustration of usefulness of this approach.

Example: an abstract syntax tree (AST) nodes of some well-defined grammar can all be inherited from a single Node class implementing a visitor pattern to handle all node types.

  • 9
    No, no and no. This is not useful and never a good solution. – Sulthan Nov 26 '13 at 14:39
  • @Sulthan I have worked with ASTs outside of the classroom, and I believe lorus does not truly understand the question. A Visitor is not a type of node on an AST, it is a separate object. It can and should know about the grammar objects. But a high level AST node should not. – user22815 Nov 28 '13 at 7:30
  • 1
    @JohnGaughan The term "knows" confuses me. The base Node class, of course, does not contain any direct references to its subclasses. But it contains an accept method with a Visitor parameter. And Visitor contains a visit method per each subclass. So, despite Node has no direct references to its subclasses, it "knows" about them indirectly, through Visitor interface. They all coupled together through it. – lorus Nov 28 '13 at 10:03
  • 1
    @Sulthan Never say never. Option type is a valid example of the case when supreclass knows about descendant one. But as Jorg said it would be marked as sealed. – Pavel Voronin Dec 2 '13 at 20:05
  • Then are agreeing: a visitor needs to know what it is visiting. – user22815 Dec 4 '13 at 2:09
1

If I write a component for a firm and later, after I've left, someone extends it for their own purposes should I be informed about that?

No!

Same with classes. Trust your instincts.

  • Job security??? – sixtyfootersdude Nov 26 '13 at 17:36
  • Your sixty foot high so I shan't argue with you :-) However, I hope my meaning was after I've gone and got another job. – Daniel Hollinrake Nov 26 '13 at 18:35

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.