Herkömmliche Softwareentwicklung versagt bei der angemessenen Umsetzung von Algorithmen.
Generische Programmierung strebt nach universell verwendbarer algorithmischer Software.

Warum generische Programmierung?

Bahnhof mit unterschiedlichen Spurweiten in Indien © Arne Hückelheim, wikipedia
Bahnhof mit unterschiedlichen Spurweiten in New Jalpaiguri, Indien

Stellen Sie sich vor, wir bräuchten für jede Automarke, ja für jedes Modell einen eigenen Straßentyp. Entweder wäre unser Land jetzt unter dem Asphalt von 100-spurigen Autobahnen begraben (konsequente Fortschreibung des westlichen Zivilisations-Modells), es gäbe nur eine einzige Automarke (Modell DDR), oder Sie müssten auf einer Fahrt von Hamburg nach München x-mal umsteigen (Modell Deutsches Reich vor 1806). Das ist nicht ganz soweit hergeholt, wie es scheint. Eine vergleichbare Situation gibt es ja bei der Eisenbahn: Man denke nur an die verschiedenen Spurweiten in Mitteleuropa, Spanien oder Russland. Und wer seinen Laptop im Ausland einstöpseln will, tut auch gut daran, an einen Adapter zu denken und sich evtl. sogar Gedanken über Spannungen und Frequenzen zu machen.

In der Welt der Software ist die Situation jedoch weitaus schlimmer. Der aktuellen Mainstream-Softwaretechnologie fehlen die Mittel, um Algorithmen angemessen umzusetzen. Die Algorithmen selbst sind ja eigentlich sehr allgemeine, mathematische Verfahren. Die Software, die solche Algorithmen implementiert, funktioniert aber oft nur unter ganz engen Begrenzungen an die Eingabe-Daten (Automodell in der Analogie), oder genauer: Sogar an die Darstellung der Eingabe-Daten (Automodell + Farbe). Wollen wir etwa die Summe einer Folge von Zahlen berechnen, würden wir für jede Kombination der folgenden Eigenschaften eine eigene Routine schreiben:

  • Datentyp der Zahlen: Fließkomma einfach oder doppelt genau, Ganzzahl mit oder ohne Vorzeichen und verschiedener Länge (Wortbreite)
  • Darstellung der Zahlenfolge: Array, Liste, Lücken-Array (z.B. Zeilen oder Spalten einer Matrix), oder gar on-the-fly berechnet

Nun scheint eine Summenberechnung ein sehr einfacher Vorgang zu sein, die man in jeder Programmiersprache in 2 Zeilen hingeschrieben hat Deswegen könnte man hier einfach die Schultern zucken und sagen, was soll's, schreiben wir es eben immer neu. (Im Tutorial sehen wir uns den Fall mal ganz genau an, und diskutieren auch, warum eine generische Version selbst hier Vorteile hat). Aber schon wenn man die Summenberechnung parallelisieren möchte, wird es weniger einfach. Es kommt dann eine weitere Dimension in der obigen Feature-Liste hinzu, nämlich das Parallelisierungsmodell (verteilter oder gemeinsamer Speicher, Vektorisierung, Thread-Modell bzw. API). Dieses würde man schon weniger gern immer wieder neu schreiben, zumal damit der Anwendungscode dann sehr eng an eine bestimmte Technologie gebunden wird (pthreads, OpenMP, TBB, OpenCL ... oder was?), die schon morgen überholt sein kann.

In der Praxis gibt es natürlich weitaus komplexere Algorithmen als die Summation, und auch weitaus mehr Möglichkeiten der Datendarstellung. All das verschärft die Situation.

Eine Implementierung für jede Kombination scheidet also im Normalfall schlichtweg aus. Damit steht man vor dem Problem, solche Algorithmen entweder immer wieder ad hoc neu umsetzen zu müssen, oder Daten immer wieder in einige wenige "Standard"-Darstellung umzukopieren (mit allen möglichen Verlusten an Performanz, Information oder Korrektheit) — es sei denn wir finden einen Weg, Algorithmen ein für alle Mal ganz universell zu implementieren.

Und dieser Wunsch markiert den Ausgangspunkt der generischen Programmierung.