In his article Designing Qt-Style C++ API from 2005, Matthias Ettrich argued that the very major benefit of static polymorphism is to make it easier to memorize APIs and programming patterns. This can not be emphasized enough. Our memory has a limited capacity, related functionalities can be understood better when they demonstrate enough similarity. In other words, but static polymorphism is the answer to the (ultimate) search of consistency.
Take a look at the screenshot. It shows a user interface created by a hypothetical framework: some radio buttons, a check box, and a push button. Now imagine if setting the text which represents the label for each individual component involves a code fragment that accesses the framework like this:
X1.value = 'Rare'; X2.value = 'Medium'; X3.value = 'Well done'; Y.option = 'Fries'; Z.caption = 'Order';
Because the code is aligned that way, it is easy to see why this is confusing. A radio button relies on
value property, a check box needs a property called
option, and finally the text for the push button comes from
caption. This demonstrates inconsistency. Once the problem is spotted, the fix is easy:
X1.value = 'Rare'; X2.value = 'Medium'; X3.value = 'Well done'; Y.value = 'Fries'; Z.value = 'Order';
This of course does not apply only to these UI elements. For example,
a slider and a progress bar can have similar names for some of their
properties since each needs a set of values to to define the range
(maximum and minimum) and the current value. An example of incosistency
is if one calles it
maximum and the other prefers
Check your favorite UI framework’s API documentation for a progress bar
and a slider and see if those properties demonstrate the principle of
Of course, this also applies to function names. Imagine if moving a point involves calling
translate whereas moving a rectangle means calling
Such a case could simply be an honest mistake, yet this indicates that
it falls through the crack as it managed to escape any possible code
Static polymorphism does not stop at the practice of choosing function names. Imagine that we have a way to define a rectangular shape by its corner (top left position) and its dimension (width and height).
corner = new Point(10, 10); dim = new Size(70, 50); R = new Rect(corner, dim);
Since it is tedious to always create two objects for the constructor, we can have another shortcut constructor that takes four values. In this variant, the parameters of the constructor represents x1, y1, x2, y2 coordinates of that rectangle.
Q = new Rect(10, 10, 80, 60);
It is likely that the second constructor was designed in isolation. The set of numbers in the above line of code has a major difference compared to that of the previous code fragment. In fact, if someone converts the Point Size version to the shortcut version, they need to use different values. The spirit of the first constructor is a pair of (x, y) and (width, height), the second constructor however expects a pair of (x1, y1) and (x2, y2). Worse, if you are familiar with the first constructor and suddenly found a code that uses the second form, you might not be alarmed that the meaning of the last two numbers is not what you have in mind.
It does not matter if you are a library author or an application developer. Next time you want to introduce a new property/function/object, scour your existing code and look for patterns that have been used again and again. Those are good data points and should not be ignored.
Now, aren’t you hungry after looking at the first example?