Imperfect Hierarchy

Much of this applies to non-hierarchical taxonomies as well - the essential problem is a set of things which have (for the most part) share a group of interesting and useful properties - but which have a few exceptions to prove the proverbial rule.

An ImperfectHierarchy is one where some attribute of a base type no longer applies to a derived type. Much of typing theory assumes that derived types can be substituted for base type objects - and that every valid operation on a base type instance is also valid on subtype instances. (This is a weaker requirement than the LiskovSubstitutionPrinciple, but one that many languages, as well as O-O theory, frequently assume.)

The real world, of course, laughs in the face of these notions. Of course, the quality of your abstractions and your tools also plays a part.

Consider an example given in ObjectOrientedSoftwareConstruction - a class hierarchy representing birds. At the root is class Bird, and it has a bunch of methods for attributes of birds and things that birds do: lay_eggs(), fly(), number_of_feathers(), etc. (We'll ignore other critters that may fly or lay eggs.) These methods will be unimplemented in the base class ("abstract" in Java speak, "pure virtual" in C++ nomenclature, "deferred" in EiffelLanguage), subclasses must provide implementations. (In a language with DynamicTyping such as SmalltalkLanguage, of course, there is no need to write unimplemented methods... this is only an issue with StaticTyping.)

Individual species of bird may be subclasses - we can have class EmperorPenguin?(), WesternMeadowlark?(), RubyThroatedHummingbird?(), etc. There may be intermediate subclasses (representing the taxonomy of birds used by scientists, or representing other ways of organizing birds into subsets, etc.)

Of course, when we get around to writing the method EmperorPenguin?.fly(), we run into a little problem... penguins cannot fly. Neither can chickens, emus, ostriches, and a whole lot of other bird species.

What to do? Lots of possibilities:

Or, you could use a language with DynamicTyping - in which no promises to allow flight are made in the base classes, and clients ought not be surprised to see DoesNotUnderstand returned from a call to "aPenguin fly" (in SmalltalkLanguage). After all, if you don't make a promise, you don't have to worry about breaking it...

Add bats to the mix. Bats can fly, but they aren't birds. Likewise with many species of insect, several (now-extinct) reptiles, and outside the realm of biology we have planes and helicopters. The difference is interesting to a biologist, but not to a cage maker. Cage makers don't care about the evolutionary history of an animal, they just care if it can fly. Hierarchies are often limited to specific perspectives. Don't get too hung up on finding a perfect hierarchy. Find one that works in a given context and use it. Interface inheritance is well suited to this approach. You can make "Bat" and "Swallow" implement an interface in the Flighted hierarchy instead of worrying about all mammals and aves.

See also ThereAreNoTypes, LimitsOfHierarchies

CategoryPolymorphism CategoryHierarchy CategoryOrganization CategoryIdealism

View edit of September 30, 2009 or FindPage with title or text search