An example helps illustrate the point. A programmer wants to create a calculator with a graphical user interface, like those provided with many desktop windowing systems. At her disposal are two off-the-shelf components: an ``infinite-precision'' arithmetic library, and a graphical user interface toolkit. With these parts at hand, the programming task seems straightforward. Unfortunately, the provider of the arithmetic library made the following design choice about the handling of errors. Assuming that the library would mostly be used in numerical analysis applications where an erroneous computation (such as division by zero) represents programmer error, the library provider chose to print an informative error message and exit the program when an error occurs. Unlike the choice of data representation and numerical algorithms, to the library provider the choice of how to handle errors is incidental; many alternatives would have been reasonable - he just happened to choose this one.
Unfortunately, this decision is incompatible with the intended ``friendliness'' of the calculator's user interface. (When causing a division by zero on a desktop calculator, one hardly expects the calculator to disappear!) Fortunately in this case, the library provider's decision about error handling does not render the library completely useless. By anticipating and handling the errors that would cause the library to exit the program, the programmer is able to use the library anyway. The cost however is high. The error detecting code in the arithmetic library must be reproduced in the calculator. Also, if the library's source code is unavailable, the programmer will have to hope that testing will ensure that the calculator's use of the library will not cause the undesirable exit.
Frequently with this type of problem, one service provider alone is not to blame. More often, two service providers make independent decisions that taken alone are fine, but in combination are incompatible. Here are some examples:
Solving these problems is an issue for ``open implementation.'' Obviously many of these problems can be solved by fiat. If everyone created their libraries in Modula 3 - one example of a modern programming language with sensible name space control, garbage collection, multiple threads-of-control, and exception handling - many of the example problems above would be mitigated, if not eliminated. However, this kind of enforced homogeneity among service providers has never existed and probably never will. Further, the nature of the problems above is that they limit the number of clients that can take advantage of a service (or conversely, limit the degree to which a service can be reused); trying to avoid the problem through forced conventions is merely another way to limit the clients that can use a service. A better solution is an open implementation approach, whose goal is to allow clients to have a tempered influence on a service provider's implementation choices. As researchers and practitioners explore the new open implementation design paradigm, incidental implementation decisions should be considered along with central ones, for they too can limit reuse.
Back to Alphabetical List of Responses
(Last Revised March 1996)