Multi-Paradigm Design
James O. Coplien
Vrije Universiteit Brussel
25 July 1999
Introduction
Multi-paradigm design [Coplien1999] helps the designer create abstractions for arbitrary domains. Object-oriented design arms the designer with tools that produce modules of a certain shape; as long as the problem domain lends itself well to object-shaped abstractions, the object paradigm works well. However, some problems (e.g., solving polynomial roots) have little to do with objects. Multi-paradigm steps above any single paradigm to help the designer choose the right paradigm for each project domain. The research at hand focuses on C++ but is equally applicable to any expressive implementation technology.
Complexity is the focus of software design. Paradigms are the rules and tools we use to divide up the world into manageable abstractions.
How does the object paradigm attack complexity? We group real-world objects into software classes. Classes capture the structure and behavior common across all their objects. Next, we can group similar classes into class hierarchies.
Both of these groupings build on analyzing commonality: we group objects into classes using abstraction. We use a slightly different set of abstracting rules to group classes into class hierarchies that form families of objects. Variabilities distinguish individual family members.
We can characterize commonality categories that describe the kinds of commonalities and variabilities: structure, behavior, name, algorithm, etc. A programming language paradigm is formally an ordered pair of such categories, one for commonality, the other for variability. For example, the object paradigm is based on commonality in structure and behavior, and regular variation in structure and in the implementation of behavior. Similar characterizations are possible for templates, overloading, and other paradigms directly expressed by programming language constructs.If we find such pairings in our application domain, multi-paradigm design will point us to the right paradigm, and the language features that capture it. My current research explores this design approach, called multi-paradigm design.
Commonality is an invariant in a good analysis. Consider solve functions in a math package with a convergance criterion of epsilon = 0.001. But for one particular instance we want a more precise solution, with epsilon = 0.00001. This difference is more than a simple variability, since it violates a predominate commonality. When a variability violates commonality, we call it a negative variability. If the variability leaves commonality invariance untouched, we call it a positive variability.
We could "solve" the above case with code like this:
void solve(double, double= 0.001) ...
void solve(double, int, double= 0.001) ...
= ...
int main() {
solve(1.2, 3.0);
solve(1.2, 2, 0.00001);
}
Here, we use overloading to capture the commonality among functions (similar semantics and behavior, different parameters and algorithm), and argument defaulting to capture the negative variability. Other C++ features such as template specialization and private inheritance also capture negative variability. Most design patterns (e.g., Template Method, State, and the two implementations of Strategy [Gamma1995]) express negative variabilities that cannot easily be expressed in language constructs.
Future research will investigate the relative power of different paradigms using a group-theoretic charactization of their symmetries.
Back to the GCSE Young Researchers Workshop Abstracts Overview.