Generic programmings targets universally usable algorithmic software.
Why Generic Programming?
Imagine, we would need a separate kind of road for each car manufacturer, or even for every car model. Our countries would either be buried under 100-lane highways (solution type western civilization), or there would be only one type of car (solution type ex-GDR), or to travel from Hamburg to Munich, one would need to change cars every n miles (solution type German empire before 1806). This vision is not so far-fetched as one might think. In the case of railways, we have different track gauges in central Europe, Spain, and Russia. And anybody thinking about plugging in her laptop abroad should remember to bring plug adapters, or even spend some thought on frequencies and voltages.
In the case of software, the situation is worse. Mainstream software technology lacks the means for the adequate implementation of algorithms. The algorithms themselves are very general, mathematical methods. Software implementing those algorithms however is generally bound to a narrowly limited kind of input data (car model in our analogy). More specifically, it is not only the kind of input data, but also its representation (color of the car). For instance, to sum a sequence of numbers, we typically need a different implementation for each combination of the following properties:
- Type (or kind) of numbers: floating point with single or double precision, signed or unsigned integers of different ranges.
- Representation of the number sequence: Array, list, sparse array (columns or rows of a matrix), or even computed on the fly.
Now, summing up numbers seems to be a quite simple thing, which can be handled in 2 lines in every programming language. So one might be tempted to say: So what? Let's just rewrite it every time. (In our tutorial we'll have a closer look on this and why it may be beneficial to use a generic component even in this case). But even with this utterly simple algorithm, things get more complicated when we are going to parallelize, vectorize (or both). We then get an additional dimension to our feature list above, which is the parallelization model (shared or distributed memory, vectorization, threading model and parallel API). And we are less likely to want to rewrite that from scratch over and over again. Besides the additional effort, this would tie our code closely to a particular parallel technology (pthreads? OpenMP? TBB? OpenCL?) — which may become obsolete tomorrow.
In reality, we have to deal with a multitude of algorithms, generally more complex than sum computations, linked with many more possible variations of data representations. All this worsens the problem.
Creating a dedicated implementation for each possible combination is in general not feasible. Thus, a programmer faces the choice to either create fresh ad-hoc implementations for the combinations she needs, or to copy data to a few "standard" representations (with all potential losses of performances, information, or correctness) — except we find a way to implement algorithms once and for all in a universal way.