Sub Typing And Sub Classing

Two terms that are often confused are subtyping and subclassing. This confusion is unsurprising, as many languages (CeePlusPlus, JavaLanguage, etc.) equate the two (more or less) - in C++, the only way to create a subtype is through subclassing. As a result, many ObjectOriented texts also treat them as equivalent or gloss over the differences. But they are two different concepts, neither of which need imply the other.

In short, subtyping is a mathematical concept having to do with substitutability, whereas subclassing is a type construction method found in most ObjectOrientedLanguages (if not all).

Subtyping

Subtyping is a mathematical relationship, ultimately related to sets. It is convenient to define a type as a set of possible values or states that an object may assume (for mutable objects, the object may transition between any value or state in the set; though not necessarily so). A subtype is, in this view, a subset and a proper subtype is a proper subset. This is known as SemanticSubtyping. This explanation is an oversimplification, but it will do.

Most modern OO languages use SyntacticSubtyping?, where types and subtypes are specified by construction. Syntactic subtyping is less powerful than semantic subtyping in that some types are difficult or impossible to create (depending on the features of the specific language). However, it's much easier to implement, and less likely to diverge. Syntactic subtyping also avoids many paradox issues that plague set-theoretic approaches - metaclasses and the like are difficult to model in SemanticSubtyping.

Some languages use a weaker approach still - nominative subtyping, wherein type/subtype relationships have to be explicitly declared, e.g., with extends clauses. CeePlusPlus and JavaLanguage are in this camp. Other languages provide structural subtyping, commonly known as DuckTyping, in which the subtype relationship is determined by feature comparison. (SmalltalkLanguage is in this category). However, all syntactic approaches still uphold the fundamental relationship of subtypes - they correspond to subsets. Substitutability still applies (up to a point; any language can allow a derived class method to do something nasty and predictable like dump core; no typechecker can deal with this).

Some of you may be asking "what about abstract base classes, or interfaces? Those don't have instances! How can a non-empty set be a subtype of the empty set?" Stay tuned.

Subclassing

Subclassing (also known as inheritance) is a method of class/object construction, wherein portions of one class or object are copied into another (with some of the copied features possibly being modified, or overridden, in the new class). In many languages, this technique is equivalent to subtyping - if class B inherits from class A, then by definition B is a subtype of the type A. Conversely, many languages don't provide any other means of creating subtypes other than subclassing. Languages in this camp include CeePlusPlus, JavaLanguage, and EiffelLanguage (though C++ does provide PrivateInheritance, which creates subclasses without subtyping - this feature is rarely used. Implementation of a JavaInterface is considered subclassing for this discussion).

There are many other ways of forming subtypes found in various languages:

In some languages, one can introduce new supertypes by the type union operator, or DuckTyping again (this time specifying fewer features).

At any rate... in languages where subtyping and subclassing are equivalent, there still is an important difference between the two. Suppose I have a base class Base, and two derived classes Derived1 and Derived2. (Assume Base has no other subclasses, direct or indirect - we're discussing nominatively typed languages like CeePlusPlus or JavaLanguage). There are several sets we can consider.

  1. The set corresponding to all (possible) objects of class Base - those objects that are created by a call to "new Base" in C++ or Java. If Base is abstract, this is empty; otherwise it may contain some elements.

  2. The sets corresponding to all possible objects of class Derived1 and Derived2. These two sets are disjoint from each other, and are also disjoint from the set of elements in class Base.

  3. The sets corresponding to all possibly objects of type Base. This set is the union of all sets in 1 and 2 above; if other subclasses of Base were to be created, their members would be added to this set. Notice that this set is larger than the set of objects of class Base.

  4. The sets corresponding to all possible objects of type Derived1 and Derived2. Since Derived1 and Derived2 are leaf classes; these two sets are the same as the class sets described in 2 above; that would not be true any more if Derived1 or Derived2 were further subclassed.

So... to answer the question posed above... the set of all objects of a type is a superset of the set of all objects of its subtypes, but the set of all objects in a particular class is (in languages like C++ or Java) disjoint from its subclasses.


See the influential paper InheritanceIsNotSubtyping


EditText of this page (last edited December 13, 2005) or FindPage with title or text search