Design Patterns – Why Is Inheritance Defined at Compile-Time?

compilationdesign-patternsinheritanceruntime

I found this statement from the gang of four's "Design Patterns" particularly odd; for some context, the authors are comparing inheritance versus composition as reuse mechanisms [p. 19]:

"…you can't change the implementations inherited from parent classes
at run-time, because inheritance is defined at compile-time."

They go on to say of composition:

"Object composition is defined dynamically at run-time through objects
acquiring references to other objects."

I am not sure why this phase distinction is important. I am familiar with compiling and inheritance but work as a JavaScript developer, so maybe I'm missing something fundamental.

Best Answer

Some languages are pretty strongly static, and only allow the specification of the inheritance relationship between two classes at the time of definition of those classes. For C++, definition time is practically the same as compilation time. (It's slightly different in Java and C#, but not very much.) Other languages allow much more dynamic reconfiguration of the relationship of classes (and class-like objects in Javascript) to each other; some go as far as allowing the class of an existing object to be modified, or the superclass of a class to be changed. (This can cause total logical chaos, but can also model real world nasties quite well.)

But it is important to contrast this to composition, where the relationship between one object and another is not defined by their class relationship (i.e., their type) but rather by the references that each has in relation to the other. General composition is a very powerful and ubiquitous method of arranging objects: when one object needs to know something about another, it has a reference to that other object and invokes methods upon it as necessary. As soon as you start looking for this super-fundamental pattern, you'll find it absolutely everywhere; the only way to avoid it is to put everything in one object, which would be massively dumb! (There's also stricter UML composition/aggregation, but that's not what the GoF book is talking about there.)

One of the things about the composition relationship is that particular objects do not need to be hard-bound to each other. The pattern of concrete objects is very flexible, even in very static languages like C++. (There is an upside to having things very static: it is possible to analyse the code more closely and — at least potentially — issue better code with less overhead.) To recap, Javascript, as with many other dynamic languages, can pretend it doesn't use compilation at all; just pretence, of course, but the fundamental language model doesn't require transformation to a fixed intermediate format (e.g., a “binary executable on disk”). That compilation which is done is done at runtime, and can be easily redone if things vary too much. (The fascinating thing is that such a good job of compilation can be done, even starting from a very dynamic basis…)

Some GoF patterns only really make sense in the context of a language where things are fairly static. That's OK; it just means that not all forces affecting the pattern are necessarily listed. One of the key points about studying patterns is that it helps us be aware of these important differences and caveats. (Other patterns are more universal. Keep your eyes open for those.)

Related Topic