iX 6/2017
S. 118
Praxis
Softwareentwicklung
Aufmacherbild

Objektorientiert oder funktional programmieren?

Die Probe aufs Exempel

Entwickler sind häufig Fans bestimmter Programmierverfahren. Doch nicht immer ist das bekannte auch das zweckmäßigste Werkzeug. Das zeigt der Vergleich von objektorientierter und funktionaler Programmierung an einem konkreten Beispiel.

Der funktionale Programmierstil ist in und gilt als kompakt, seine Anwendungen sieht man insbesondere im technischen und mathematischen Bereich. Ebenso haben funktionale Elemente Einzug in viele ursprünglich nicht funktionale Programmiersprachen gehalten. Wie sieht es in der Praxis aus? Wann sollte man lieber funktional statt objektorientiert programmieren? Ein nicht ganz triviales Beispiel zeigt, wie sich die beiden Verfahren schlagen. Aus dem Vergleich beider Umsetzungen und den Erfahrungen lassen sich Erkenntnisse für den Einsatz des funktionalen Vorgehens ableiten.

Objektorientierung gilt seit Jahren als Standard in der Programmierung. Man kann alle erdenklichen Aspekte der realen Welt in Klassen und Objekte zwingen. Sowohl Business- und Webanwendungen als auch Spiele werden meist objektorientiert modelliert und implementiert. Grundsätzlich ist Objektorientierung nicht alternativlos (siehe Kasten „Programmierparadigmen“), andere Modelle können genauso zum Ziel führen. Rein funktionale Sprachen wie Haskell erfordern es, dass der Programmierer strikt funktional arbeitet. Viele moderne Programmiersprachen bevorzugen zwar ein Paradigma, unterstützen jedoch mehrere.

Für das .NET-Framework hat Microsoft die Sprache F# entwickelt, die funktionales Programmieren in den Vordergrund stellt. Als .NET-Sprache erlaubt sie auch objektorientiertes Programmieren: Man kann Klassen erstellen, Objekte erzeugen und deren Methoden aufrufen. Gleichzeitig erweitert Microsoft C#, die primäre Sprache für .NET-Applikationen, um funktionale Aspekte. Das Programmierparadigma ist damit weniger abhängig von der gewählten Sprache. Unter Windows erlaubt es Visual Studio, Projekte innerhalb einer Solution in unterschiedlichen Sprachen zu schreiben. So kann der Entwickler das zur Aufgabe und seinen Vorlieben passende Paradigma wählen.

Eine Aufgabe, zwei Wege zur Lösung

Eine problemnahe Ausdrucksweise und ein erheblich kürzerer Quelltext gelten als Vorzüge funktionalen Programmierens – insbesondere in mathematischen oder technischen Zusammenhängen. Kurzer Code vereinfacht wiederum die Wartung und reduziert die Fehleranfälligkeit. Ob allerdings wirklich ein Vorgehen besser ist als ein anderes, ist meist nicht festzustellen. Bei funktionalen Beispielen fehlt in der Regel eine vergleichbare objektorientierte Alternative. Ebenso stellt sich beim Fortschreiben oder Sanieren eines Projekts gelegentlich die Frage, ob der Wechsel zum funktionalen Vorgehen die Wartung erleichtern könnte. Diese Informationslücke will der vorliegende Artikel füllen. Er geht eine Aufgabe aus der objektorientierten sowie der funktionalen Perspektive an und untersucht, ob der Umstieg von ersterer Vorteile bringt.

Als Praxisprojekt dient eine Aufgabe aus dem Compilerbau: ein Parser für mathematische Funktionen, den so oder ähnlich viele Programme einsetzen (siehe Kasten „Beispiel in der Praxis“). So ein Parser muss Muster in Zeichenketten erkennen, wobei er häufig Rekursion verwendet. Beide Aspekte sind Merkmale funktionaler Sprachen, es gibt sie aber auch in anderen Idiomen. Bisher existiert der Parser rein objektorientiert in C#, im Experiment entsteht er in F# neu.

Vom Term zum Syntaxbaum

Die lexikalische Analyse zerlegt den String in Symbole, aus denen die syntaktische Analyse den Syntaxbaum erstellt. Mit ihm lassen sich anschließend Funktionswerte berechnen (Abb. 1).

Unabhängig von der gewählten Umsetzung ist das Ziel zu beschreiben. Beim mathematischen Funktionsparser lautet es: Der Ausdruck (Term) muss in seine Bestandteile wie Operationen, Zahlen, Funktionen und Variablen zerlegt werden. Sie stehen in einem strukturellen Zusammenhang, den ein Syntaxbaum am besten beschreibt. Liegt er vor, kann man ihn unterschiedlich einsetzen, beispielsweise den Ausdruck für bestimmte Werte einer Variablen berechnen oder ihn nach mathematischen Regeln umformen. Sowohl das Generieren des Syntaxbaums als auch seine Verwendung erfolgt zweckmäßigerweise rekursiv. Das Prinzip zeigt Abbildung 1.

Das Wichtigste zum funktionalen Programmieren in Kürze: Es baut auf dem mathematischen Begriff der Funktion auf und kombiniert kleine, spezialisierte, möglichst generische Einheiten zur Lösung einer größeren Aufgabe. Das erlaubt ein hohes Maß an Abstraktion und führt bei richtiger Anwendung zu ausdrucksstarkem Programmcode. Ein rein funktionales Programm besteht lediglich aus Funktionsaufrufen. Eigenständige Wertzuweisungen existieren nicht, alle Elemente können als Funktionen aufgefasst werden.