Imperative und funktionale Programmierung

In irgendeiner Weise muss ein Entwickler sein Problem in Programmform beschreiben, damit der Computer es letztendlich ausführen kann. Hier gibt es verschiedene Beschreibungsformen, die wir Programmierparadigma nennen. Bisher haben wir uns immer mit der imperativen Programmierung beschäftigt, bei der Anweisungen im Mittelpunkt stehen. Wir haben im Deutschen den Imperativ, also die Befehlsform, die sehr gut mit dem Programmierstil vergleichbar ist, denn es handelt sich in beiden Fällen um Anweisungen der Art „tue dies, tue das“. Diese „Befehle“ mit Variablen, Fallunterscheidungen, Sprüngen beschreiben das Programm und den Lösungsweg.

Zwar ist imperative Programmierung die technisch älteste, aber nicht die einzige Form Programme zu beschreiben; es gibt daneben die deklarative Programmierung, die nicht das „wie“ zur Problemlösung beschreibt, sondern das „was“, also was eigentlich gefordert ist ohne sich in genauen Abläufen zu verstricken. Auf den ersten Blick klingt das abstrakt, aber für jeden, der schon einmal

· einen Selektion wie im *.html auf der Kommandozeile genutzt,

· eine Datenbankanfrage mit SQL geschrieben,

· eine XML-Selektion mit XQuery getätigt,

· ein Build-Skript mit Ant oder make formuliert,

· eine XML-Transformation mit XSLT beschrieben hat, wird das Prinzip kennen.

Bleiben wir kurz bei SQL, um einen Punkt deutlich zu machen. Natürlich ist im Endeffekt die Abarbeitung der Tabellen und Auswertungen der Ergebnisse von der CPU rein imperativ, doch es geht um die Programmbeschreibung auf einem höheren Abstraktionsniveau. Deklarative Programme sind üblicherweise wesentlicher kürzer und damit kommen weitere Vorteile wie leichtere Erweiterbarkeit, Verständlichkeit ins Spiel. Da oftmals deklarative Programme einen mathematischen Hintergrund haben, lassen sich die Beschreibungen leichter formal in ihrer Korrektheit beweisen.

Deklarative Programmierung ist ein Programmierstil, und eine deklarative Beschreibung braucht eine Art „Ablaufumgebung“, denn SQL kann zum Beispiel keine CPU direkt ausführen. Aber statt nur spezielle Anwendungsfälle wie Datenbank- oder XML-Abfragen zu behandeln, können auch typische Algorithmen deklarativ formuliert werden, und zwar mit funktionaler Programmierung. Damit sind imperative Programme und funktionale Programme gleich mächtig in ihren Möglichkeiten.

Funktionale Programmierung und funktionale Programmiersprachen

Bei der funktionalen Programmierung stehen Funktionen im Mittelpunkt und ein im Idealfall zustandsloses Verhalten, in dem viel mit Rekursion gearbeitet wird. Ein typisches Beispiel ist die Berechung der Fakultät. Es ist n! = 1 · 2 · 3 · … · n, und mit Schleifen und Variablen, dem imperativen Weg, sieht es so aus:

public static int factorial( int n ) {

int result = 1;

for ( int i = 1; i <= n; i++ )

  result *= i;

return result;

}

Deutlich sind die vielen Zuweisungen und die Fallunterscheidung durch die Schleife abzulesen; die typischen Indikatoren für imperative Programme. Bei der rekursiven Variante ist das ganz anders, hier gibt es keine Zuweisungen im Programm und die Schreibweise erinnert an die mathematische Definition:

public static int factorial( int n ) {

return n == 0 ? 1 : n * factorial( n – 1 );

}

Mit der funktionalen Programmierung haben wir eine echte Alternative zur imperativen Programmierung. Die Frage ist nur: Mit welcher Programmiersprache lassen sich funktionale Programme schreiben? Im Grunde mit jeder höheren Programmiersprache! Denn funktional zu programmieren ist ja ein Programmierstil, und Java unterstützt funktionale Programmierung, wie wir am Beispiel mit der Fakultät ablesen können. Da das im Prinzip schon alles ist, stellt sich die Frage, warum funktionale Programmierung einen so schweren Stand hat und bei den Entwicklern gefürchtet ist. Das hat mehrere Gründe:

Lesbarkeit. Am Anfang der funktionalen Programmiersprachen steht historisch LISP aus dem Jahr 1958, eine sehr flexible, aber schwer zu lesende Programmiersprache. Unsere Fakultät sieht in LISP so aus:

(defun factorial (n) (if (= n 1) 1 (* n (factorial (- n 1)))))

Die ganzen Klammern machen die Programme nicht einfach lesbar und die Ausdrücke stehen in der Präfix-Notation – n 1 statt der üblichen Infix-Notation n – 1. Bei anderen funktionalen Programmiersprachen ist es anders, dennoch führt das zu einem gewissen Vorurteil, dass alle funktionalen Programmiersprachen schlecht lesbar sind.

Performance und Speicherverbrauch. Ohne clevere Optimierungen von Seiten des Compilers und der Laufzeitumgebung führen insbesondere rekursive Aufrufe zu prall gefüllten Stacks und schlechter Laufzeit.

Rein funktional. Es gibt funktionale Programmiersprachen, die als „rein“ oder „pur“ bezeichnet werden und keine Zustandsänderungen erlauben. Die Entwicklung von Ein-/Ausgabeoperationen oder simplen Zufallszahlen ist ein großer Akt, der für normale Entwickler nicht mehr nachvollziehbar ist. Die Konzepte sind kompliziert, doch zum Glück sind die meisten funktionalen Sprachen nicht so rein und erlauben Zustandsänderungen, nur Programmierer greifen so selten wie nötig darauf zurück.

Funktional mit Java. Wenn es darum geht nur mit Funktionen zu arbeiten, kommen Entwickler schnell zu einem Punkt, dass Funktionen andere Funktionen als Argumente übergeben oder Funktionen zurückgeben. So etwas lässt sich in Java in der traditionellen Syntax nur sehr umständlich schreiben, dass alles so unlesbar wird, dass der ganze Vorteil der kompakten deklarativen Schreibweise verloren geht.

Aus heutiger Sicht stellt sich eine Kombination aus beiden Konzepten als zukunftsweisend da. Mit der in Java 8 eingeführten Schreibweise der Lambda-Ausdrücke sind funktionale Programme kompakt und relativ gut lesbar und die JVM hat gute Optimierungsmöglichkeiten. Java ermöglicht beide Programmierparadigmen und Entwickler können den Weg wählen, der für eine Problemlösung gerade am Besten ist. Diese Mehrdeutigkeit schafft natürlich auch Probleme, denn immer wenn es mehrere Lösungswege gibt, entstehen Auseinandersetzungen um die Beste der Varianten – und hier kann von Entwickler zu Entwickler eine konträre Meinung herrschen. Funktionale Programmierung hat unbestritten Vorteile und das wollen wir uns genau anschauen.

Über Christian Ullenboom

Ich bin Christian Ullenboom und Autor der Bücher ›Java ist auch eine Insel. Einführung, Ausbildung, Praxis‹ und ›Java SE 8 Standard-Bibliothek. Das Handbuch für Java-Entwickler‹. Seit 1997 berate ich Unternehmen im Einsatz von Java. Sun ernannte mich 2005 zum ›Java-Champion‹.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.