Shallow Hierarchies

Over on IsComputerScience, Aamod Sane makes a claim about the desirability of shallow hierarchies and gives a number of plausible reasons for why shallow hierarchies are preferable to deep ones (E.g. his argument has FaceValidity?).

But, I wonder about this. What are the general construction principles for hierarchies. I've noticed several environmental factors that influence hierarchy design. For example considering programmers:

Loose typers prefer to use composition and have shallow hierarchies
Strong typers tend to prefer deeper hierarchies

Another factor:

In strongly typed languages, the availability of generics flattens out inheritance hierarchies as well.

So does the existence of a reusable codebase:

The availability of a well-designed library promotes designs wherein tasks are delegated to library objects

On the other hand, strong typing tends to discourage composition:

When you have to manually type all the methods and explicitly forward the calls to "the real object", designing objects that are really just reified associations for 3 or 4 other objects begins to look ugly.

But these are all factors that lie outside the fundamental question: What does a good class hierarchy look like ?

My own preference is for deep hierarchies wherein each layer adds a little bit of functionality. There's something deeply and profoundly pleasing about having the inheritance hierarchy reflect the increasing level of specialization of objects. That is, I really like having "Terrier" between "Dog" and "Yorkshire Terrier" even if it adds very little in terms of functionality.

-- WilliamGrosso


It's hard to separate out language-specific issues, but we should try. Firstly, you've identified strong typing as a factor, where you probably mean manifest typing. Having to keyboard explicit type declarations all over the place is a pain, and inheritance of type is a way of reusing them. A language with static type inferrance could be different.

Currently languages use an explicit sub-type hierarchy. Java separates it from the subclass hierarchy (ie interfaces), but its still explicit. If we had static type checking but implicit type conformance, that would reduce another need for deep type hierarchies.

Another issue is that people traditionally specify the interface between client and server classes much more than between base class and derived class. For example, Eiffel allows derived classes to access all of the base class's implementation; there is no "private" keyword. This is the main reason why a large aggregation system appears easier to manage than a large subclassing system.

Then as you say, not having language support for delegation makes that more laborous.

For ShallowHierarchies to be a pattern I'd agree with, these factors need to be included in its context. -- DaveHarris


I think that deep hierarchies make code much harder to understand. Inevitably, in your method/member function implementations, you use many services (and maybe even data members, depending on language and style) from base classes. When reading a function and trying to comprehend it, one looks for variables locally, then as class members of the local class. Similarly for functions. You look for function calls as member function of the current class, then maybe local statics (I'm thinking mostly C++-flavor here) in and as base class members or global functions. Calls that are obviously member function calls on a specific object can be more easily traced by looking for the object definition first, then at that object's class, then at its base classes. The deeper your hierarchy, the harder it tends to be to find this stuff. I've spent a lot of time trying to grok systems designed with deep hierarchies, and it's frustrating. -- DanMuller


See also DeepClassHierarchies CategoryHierarchy


EditText of this page (last edited September 30, 2006) or FindPage with title or text search