This chapter is a condensed overview of the first part of the book on Generative Programming [Czarnecki00].
Library design is language design. [Stroustrup]
Course Goal
To learn how to implement software libraries, such as STL, CGAL, LEDA, ..., that have a focus on algorithms and data structures. To learn advanced programming techniques in C++, such as templates, generic programming, object-oriented design, design patterns, and large-scale C++ software design.
We will approach library design from different angles:
In contrast to the software design of an application, the design for a software library is an obvious quality criterion for the user, i.e., software developer using the library. In addition, the library designer is more often faced with the problem of a greenfield design, i.e., the library designer does not know the specific needs of the (potentially many) library user.
We like to emphasize here that the user's point of view of library design can differ quite drastically from the library designers point of view. The use of a library can be much easier than its implementation. A complicated implementation technique for a library does not necessarily make the library complex for the user. However, maintainability and the required training of the library developers have to be taken into account.
Generative Programming (GP) is a software engineering paradigm based on modeling software system families such that, given a particular requirements specification, a highly customized and optimized intermediate or end-product can be automatically manufactured on demand from elementary, reusable implementation components by means of configuration knowledge.
So, generative programming has a strong focus on reuse. This is reflected in the analysis and design phase of the software development that is broken into two tracks: the domain engineering develops the design for the system families, and application engineering develops the design for a specific product created with specific members of the system families. So, domain engineering is design for reuse, and application engineering is design with reuse.
We focus on domain engineering and later on domain engineering for algorithm libraries. Domain engineering breaks down into the following tasks:
In more detail from the domain engineering method DEMRAL [Czarnecki00]:
Besides [Czarnecki00] see also the Multi-Paradigm Design in [Coplien98] for details on domain analysis.
A feature model represents the common and the variable features of concept instances and the dependencies between the variable features. It consists of a feature diagram and some additional information described later. The feature diagram is a tree with a concept as root and features in each node. The following decorations on the tree edges are distinguished:
![]() |
![]() |
![]() |
![]() |
| Mandatory features: all features have to be present. | Optional features: any feature can be chosen optionally. | Alternative features: exactly one feature has to be chosen. | Or-features: at least one feature has to be chosen. |
In principle, all combinations of decorations are allowed. In particular, the arcs indicating alternative or or-features do not have to cover all edges of a node. For example, two arcs could cover two groups, creating two sets of children.
Some combinations are redundant and are normalized as follows:
![]() |
![]() |
| Optional alternative features: If one feature in an alternive is optional then all features in that alternative are optional. | Optional or-features: If one feature in an or-feature is optional then the `at least one feature' requirement becomes meaningless and we normalize to a set of optional features. |
Features can be direct children of the concept root node or of other feature nodes. If they are direct children of another feature node then they are only considered if the parent feature has been chosen.
Feature diagrams are a compact notation to record the set of feasible combinations of features of a concept. Let's consider an example:
In words: a car must have a car body, a transmission, an engine, and it can optionally pull a trailer. Note that although it looks like a physical decomposition, features can be arbitrary predicate statements, such as `maximum speed is 100mph', and the box `transmission' is read as `the car has a transmission'.
In the second layer of the tree, we see the transmission can be either automatic or manual, but not both at the same time (alternative feature). The car must have an engine that is electric or gasoline powered. However, it can have both types of engines at the same time (or-feature).
So the feature set encoded in this feature diagram is, written in a set notation:
{
{Car body, {Automatic}, {Electric}},
{Car body, {Automatic}, {Electric}, Pulls trailer},
{Car body, {Manual}, {Electric}},
{Car body, {Manual}, {Electric}, Pulls trailer},
{Car body, {Automatic}, {Gasoline}},
{Car body, {Automatic}, {Gasoline}, Pulls trailer},
{Car body, {Manual}, {Gasoline}},
{Car body, {Manual}, {Gasoline}, Pulls trailer},
{Car body, {Automatic}, {Electric, Gasoline}}
{Car body, {Automatic}, {Electric, Gasoline}, Pulls trailer},
{Car body, {Manual}, {Electric, Gasoline}}
{Car body, {Manual}, {Electric, Gasoline}, Pulls trailer},
}
We have some information associated with a feature diagram
We give some more options for the binding mode, i.e., the binding time of a variable feature:
std::list<int>
Brain storming would be a possible technique to get a first set of concepts and features in the domain analysis. A variant of brain storming, known as MetaMind, uses written notes instead of voicing ideas freely in a group. Voicing ideas tends to hinder creativity since a major opinion or idea could dominate the session.
For MetaMind, a neutral organizer writes a central question on the board. The participants have about 10 minutes to write their free associations on index cards, preferably single words or short phrases, each one on one card. The participants tend to be busy for the first few minutes. It is important to continue a few minutes past the first rush of obvious answers. Thereafter the cards are pinned on a board in an unorganized manner. Unclear cards have to be clarified, duplicates and synonyms are removed. Then, the organizer moderates a discussion about how to relate the cards to each other, for example commonalities, abstractions, etc. The outcome is a set of concepts and features, relations among feature that lead to feature diagram with annotations, for example, commonalities and variablities.
Another way of getting started are predefined feature starter sets. Specifically for our area of algorithm library design the feature starter sets for ADTs and for algorithms from [Czarnecki00] can be used. Here is the set for ADTs:
For container like ADTs we can also consider:
The feature starter set for algorithms:
From software engineering we list some general design goals one should keep in mind:
The famous Occam's razor:
"Pluralitas non est ponenda sine neccesitate" or "plurality should not be posited without necessity."
The words are those of the medieval English philosopher and Franciscan monk William of Ockham (ca. 1285-1349). It leads to the useful KISS (Keep It Simple, Stupid) principle that can be used to fend of "creeping featurism".