Die Essenz objektfunktionaler Programmierung und das praktische Potential von Scala

2 Kommentare

Die Begriffe „objektfunktional“ und „objektfunktionale Programmierung“ hört man immer wieder im Kontext der Softwareentwicklung. Aber wie sieht der objektfunktionale Ansatz aus und welche Vorteile hat er? Ist die Objektorientierung oder der funktionale Ansatz allein nicht schon gut genug? Und was hat das alles mit Scala zu tun?

Objektfunktional

Nicht-triviale Software muss zwei Arten von Verhalten realisieren: Sie muss Dinge berechnen und Dinge bewirken. Beispielsweise könnte eine Software berechnen, was als nächstes auf dem Bildschirm auszugeben ist, und diese Ausgabe dann vornehmen. Letzteres lässt sich auch als das Bewirken eines Effekts bezeichnen. Oft werden alle Effekte undifferenziert als Seiteneffekte bezeichnet; es macht aber Sinn zu unterscheiden in essentielle Effekte und in Seiteneffekte. Essentielle Effekte sind Teil der Anforderungen und nicht zu vermeiden: Soll etwas auf dem Bildschirm ausgegeben werden, muss es dort ausgegeben werden. Bei Seiteneffekten handelt es sich hingegen um Effekte, die eigentlich nicht notwendig, nicht interessant oder sogar unerwünscht sind und nur als Artefakt des eigentlich gewünschten Verhaltens auftreten; beispielsweise arbeitet die imperative Programmierung intensiv mit solchen Seiteneffekten, um Berechnungen vorzunehmen.

Objektorientierte Programmierung ist traditionell imperativ geprägt und das Verändern von Objekten und Objektreferenzen, und damit Seiteneffekte, sind ein ständiger Begleiter. Funktionale Programmierung hingegen hat den Schwerpunkt im Transformieren von Werten: Aus Werten werden in der Regel andere Werte berechnet, Werte und Wertereferenzen dabei aber nicht verändert.

Was passiert jetzt, wenn die transformierten Werte Objekte sind? Wir gelangen zu einer möglichen Definition objektfunktionaler Programmierung:

Objektfunktionale Programmierung ist ein Programmieransatz, der das Transformieren von Objekten in den Mittelpunkt stellt und sich hierfür sowohl objektorientierter als auch funktionaler Mittel und Prinzipien bedient. Ein Bewirken von Effekten im Allgemeinen sowie ein Verändern von Objekten und Objektreferenzen im Speziellen erfolgt nur sehr dosiert, für andere Codeteile möglichst transparent und möglichst getrennt von transformativem Code.

Bei der objektfunktionalen Programmierung wird der Software mit Mitteln der Objektorientierung eine zweckmäßige Struktur aufgeprägt, die die lokale Änderbarkeit und Verständlichkeit des Codes fördert; Daten und Verhalten werden zusammengeführt; Zugriffsmodifikatoren werden verwendet, um möglichst nur sinnvolle Abhängigkeiten zuzulassen. Funktionale und viele traditionell eher funktionalen Sprachen zugeordnete Features werden verwendet, um möglichst auf das Verändern von Objekten und Objektreferenzen verzichten und auch im Feingranularen leicht modular bleiben zu können, beispielsweise mit Funktionen als leichtgewichtiger Alternative zum Strategy Pattern. Wie in der funktionalen Programmierung üblich, wird Software in möglichst effektfreie und effektbehaftete Teile aufgeteilt und Effekte werden für andere Codeteile möglichst transparent gestaltet; auf diese Weise sind große Teile des Codes überhaupt nicht von den Nachteilen betroffen, die Effekte beispielsweise für lokale Verständlichkeit und modulare Kombinierbarkeit mit sich bringen.

Anders als bei traditioneller Objektorientierung sind Objekte in der Regel, zumindest von außen betrachtet, unveränderlich; Methoden berechnen normalerweise, bewirken aber keine beobachtbaren Effekte. Anders als bei der funktionalen Programmierung arbeiten Funktionen weniger auf passiven Datenstrukturen; stattdessen treten sie oft in Form von Methoden auf, die zu Objekten bzw. Objekttypen gehören und Zugriff auf deren nicht öffentliche Daten und nicht öffentliches Verhalten haben.

Geeignete Mechanismen werden verwendet, um essentielle Effekte wie beispielsweise gewollte Bildschirmausgaben zu realisieren; diese Mechanismen können recht unterschiedlich ausfallen.

Warum objektfunktional?

Bei der Softwareentwicklung geht es nicht nur darum, das gewünschte Verhalten „irgendwie“ abzubilden. Entwicklung und Weiterentwicklung sollen auch effizient sein und die Qualität der Software hoch. Sowohl die objektorientierte Programmierung als auch die funktionale Programmierung unterstützen dies bis zu einem gewissen Grad, jeder Ansatz auf seine eigene Weise.

Beim objektorientierten Ansatz ist die traditionell imperative Herangehensweise aber problematisch. Positive Eigenschaften, die dieser Ansatz auf die eine Weise fördert, werden hier durch den traditionell imperativen Fokus auf andere Weise wieder konterkariert, insbesondere lokale Verständlichkeit und modulare Kombinierbarkeit. Hinzu kommt, dass veränderbare Objekte nicht ohne weiteres sicher parallel verwendbar sind und der rein objektorientierte Ansatz im Kleinen oft zu schwergewichtig ist. Der funktionale Ansatz glänzt hier hingegen mit leichtgewichtigen Features sowie seiner Minimierung und Isolierung von Effekten.

Kommentare

  • Stefan Zörner

    31. August 2015 von Stefan Zörner

    Hallo Martin,

    vielen Dank für den schönen Beitrag. Das Wort objektfunktional höre ich gar nicht so oft, aber das hat immerhin dazu geführt, dass ich Deinen Artikel gelesen habe … 😉

    Eine Frage hätte ich allerdings: Du schreibst: „… beispielsweise arbeitet die imperative Programmierung intensiv mit solchen Seiteneffekten, um Berechnungen vorzunehmen.“

    Kannst Du da ein Beispiel nennen? In C z.B. …

    Herzliche Grüße,
    StefanZ

    • Martin Lau

      1. September 2015 von Martin Lau

      Hallo Stefan,

      hier ein Beispiel für eine Java-Methode, die mit Hilfe eines Seiteneffektes eine Berechnung vornimmt:

      public static BigInteger sum(List<BigInteger> summands) {BigInteger sum = BigInteger.ZERO;
       
        for(BigInteger s : summands) { 
      		
          sum = sum.add(s);
        }

    	
       
        return sum;}

      Dieses Beispiel ist noch vergleichsweise harmlos. Allerdings berechnen wir hier auch nur eine simple Summe von BigIntegers, der Seiteneffekt ist lokal und wir verändern zwar eine Objektreferenz aber keine Objekte.

      Wir müssen uns aber bereits hier fragen, wie wir mit potentiellen nicht-lokalen Seiteneffekten anderen Codes umgehen: Die reingereichte Liste summands ist potentiell veränderbar und kann theoretisch jederzeit von außen verändert werden. Deshalb und auch wenn wir komplexere Berechnungen vornehmen, wir nicht nur Objektreferenzen sondern auch den Zustand von Objekten verändern, mit komplexeren Objekten als BigIntegers arbeiten und auch selbst nicht-lokale Seiteneffekte bewirken, ist es mit der Harmlosigkeit sehr schnell vorbei.

      Beste Grüße
      Martin Lau

Kommentieren

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