Unterschied funktionial <-> OO anhand von Scala <-> Java

Kababär

Top Contributor
Hi,

ich hatte vor einiger Zeit mal einen Thread eröffnet, um herauszufinden, welche Programmiersprache ich nach Java (meiner ersten) angehen könnte und bin bei C/C++ gelandet.
Aber letztens habe ich nochmal darüber nachgedacht, wie sinnig das ist und kam zu dem Entschluss, dass es Unsinn wäre, weil die Anwendungsgebiete ja beinahe die gleichen sind. Auch sind beide imperativ und meinen Horizont kann ich viel mehr erweitern, wenn ich nicht nur eine andere Sprache, sondern auch direkt ein neues Konzept mitlerne. Aber ohne mir überhaupt eine Sprache speziell angeguckt zu haben, hatte ich schon ein Problem beim Wechsel von Imperativ (näher: OO) zu Funktional.
Nicht mehr das WIE, sondern das WAS zu betrachten, klingt einfacher. Dennoch frage ich mich WIE ich das Ganze zu implementieren habe.
Dieses Tutorial (https://scalatutorial.wordpress.com/) habe ich mir angeguckt: er wollte vom Imperativen zum Funktionalen übergehen, aber dabei ist es dann irgendwann auch geblieben, denn er erklärt vermehrt die Funktionen, Datenstrukturen anhand des Imperativen
(Oder ist da was an mir vorbei gegangen? Bis auf die gewöhnungsbedürftige Syntax und Berücksichtigung von Sonderfälllen in der Semantik, sieht das so aus wie in Java (ebenso die Logik).
Dann bin ich auf diese Seite gestoßen (http://www.scala-lang.org/docu/files/ScalaByExample.pdf, Seite 3;Chapter 2;A First Example) und im Prinzip stelle ich beim Vergleich eigentlich nur fest, dass die Funktionale Variante einfach nur abstrakter ist, als würde ich mich nur auf die vorhandenen Bibliotheken und auf die Semantik der Syntax beschränken. Stimmt das?
Oder gilt das nur in diesem speziellen Fall?
Ich hatte mal kurz etwas mit XSL zu tun, das war ja auch funktional und ich konnte damit eine XML mit Java transformieren. Ist XSL auch eine Skriptsprache?
 

Flown

Administrator
Mitarbeiter
(Oder ist da was an mir vorbei gegangen? Bis auf die gewöhnungsbedürftige Syntax und Berücksichtigung von Sonderfälllen in der Semantik, sieht das so aus wie in Java (ebenso die Logik).
Dann bin ich auf diese Seite gestoßen (http://www.scala-lang.org/docu/files/ScalaByExample.pdf, Seite 3;Chapter 2;A First Example) und im Prinzip stelle ich beim Vergleich eigentlich nur fest, dass die Funktionale Variante einfach nur abstrakter ist, als würde ich mich nur auf die vorhandenen Bibliotheken und auf die Semantik der Syntax beschränken. Stimmt das?
Ich beginne damit mal, dass Scala eine objekt-funktionale Programmiersprache ist. Es verbindet somit OOP und FP. Da Scala auf der JVM läuft und Java Code integrieren kann, kann das auch mal ähnlich aussehen. Doch FP und OOP sind grundverschiedene Sachen.
Fangen wir mit OOP an: Hier steht klar das Objekt im Vordergrund und die Eigenschaften, die damit verbunden werden. Diese Eigenschaften können nach belieben verändert werden und mit ihnen gearbeitet werden. (Jetzt in Java gesehen:) Klassen zählen als Baupläne und deklarieren, was die Eigenschaften (State + Operationen). Hier ist das WIE entscheidend. WIE abstrahiert eine Klasse die Realität und WIE löst sie Probleme. Ich brech hier mal ab, denn OOP ist so viel mehr und behandelt so viele Themen (hier empfehle ich einfach mal im Internet nach Büchern und Definitionen zu suchen).

FP: Hier steht die Funktion im Vordergrund und das kann man auch Mathematisch sehen (wenn man Haskell etc. betrachtet). Man hat Eingabeparameter und aufgrund dieser wird - idealerweise immer das gleiche Ergebnis bei gleicher Eingabe - ein Ergebnis errechnet. Diese Funktionen können jetzt auch als Argumente an andere Funktionen weitergereicht werden. So können Standardoperationen (wie z.B. Filtern/Sortieren/Iterieren/...) abstrahiert und Allgemein gehalten werden. Es geht auch noch weiter, denn Funktionen können auch Funktionen zurückliefern und das ist eine der wichtigsten Eigenschaften von FP.
(Bitte wieder hier selbst nachlesen, denn das ist auch nur ein ganz kleiner Ausschnitt aus FP)

Nehmen wir das Beispiel des Quicksort Algorithmus aus dem Scala-Lang-Doc her.
Code:
def sort2(xs: Array[Int]) {
  def swap(i: Int, j: Int) {
    val t = xs(i); xs(i) = xs(j); xs(j) = t
  }
  def sort1(l: Int, r: Int) {
    val pivot = xs((l + r) / 2)
    var i = l;
    var j = r
    while (i <= j) {
      while (xs(i) < pivot) i += 1
      while (xs(j) > pivot) j -= 1
      if (i <= j) {
        swap(i, j)
        i += 1
        j -= 1
      }
    }
    if (l < j) sort1(l, j)
    if (j < r) sort1(i, r)
  }
  sort1(0, xs.length - 1)
}
Diese Impelemntierung würde auch in Java ähnlich aussehen. Eventuell wäre die Rekursion jetzt noch Iterativ, aber das kann ja als Übung gesehen werden.
Hier wird explizit mit States gearbeitet (was nicht sehr dem FP Konzept entspricht). Das heißt explizite Iteration und Laufvariablen. Man muss auch Grenzfälle uvm. berücksichtigen.

Jetzt zu dem FP Code:
Code:
def sort(xs: Array[Int]): Array[Int] = {
  if (xs.length <= 1) xs
  else {
    val pivot = xs(xs.length / 2)
    Array.concat(
      sort(xs filter (pivot >)),
      xs filter (pivot ==),
      sort(xs filter (pivot <))
    )
  }
}
Grundsätzlich hilft Rekursion bei FP oftmals mehr als Iteration. Also: Hier wird nicht das WIE beschrieben sondern das WAS, denn Iteration ist implizit gestaltet und Verhalten wird mit Funktionen (Lambdaexpressions) beschrieben.
Ausgeschrieben (mit Lambda) sieht die Funktion so aus:
Code:
def sort(xs: Array[Int]): Array[Int] = {
  if (xs.length <= 1) xs
  else {
    val pivot = xs(xs.length / 2)
    Array.concat(
      sort(xs.filter(x => pivot > x)),
      xs.filter(x => pivot == x),
      sort(xs filter (pivot < _)))
  }
}
Hier sieht man die Stärke von OFP. Alle Operatoren sind selbst Funktionen und können auch so verwendet werden. Alle Zwischenergebnisse (Arrays nach dem Filtern) sind Immutable und nur ein Snapshot, somit könnte dieser Algorithmus auch leicht parallelisiert werden, da der Urzustand des Arrays nie verändert wird. Grenzfälle braucht man keine abzudecken, denn es wird nur der Algorithmus implementiert mit divide-and-conquer.

Konkret kann ich deine Frage nicht beantworten, denn beide Konzepte OOP und FP (respektive OFP) sind gleichmächtig und die Stärken sind woanders anberaumt. Was einem jetzt besser liegt und gefällt ist Geschmackssache und muss jeder für sich selbst entscheiden. Ich hoffe ich konnt dir mit diesem kleinen Exkurs ein wenig die Unterschiede aufzeigen. Bei Weitem kann ich dir hier nicht alle Stärken von OFP aufzeigen, wie Pattern-Matching, Case Classes, ADTs, simple DSL Implementierungen, ... .
Prinzip stelle ich beim Vergleich eigentlich nur fest, dass die Funktionale Variante einfach nur abstrakter ist
Kann man fast so sehen. Sie erlaubt eben gängige Muster zu abstrahieren und Verhalten zu injezieren (kann mit OOP simuliert werden).
als würde ich mich nur auf die vorhandenen Bibliotheken und auf die Semantik der Syntax beschränken
Nein. Aber vorhandene Syntax erleichtert vieles - sieht man am obigen Beispiel mit impliziten Lambdaexprssions, Infix-Notation, ... - am Programmieren und am Lesefluss (für ein geübtes Auge auf jedenfall!). Vorhandene Bibliothek ist schon sehr mächtig, die man auch sehr oft nutzen kann und für 99% aller Probleme verwenden kann.

Am besten du versuchst Projekte in Scala (oder OFP/FP) zu lösen und erkennst, das vieles einfacher ist, wenn man auch die Logik etwas funktionaler gestaltet (ist teilweise in Java 8 eingeführt worden)!

Ich hatte mal kurz etwas mit XSL zu tun, das war ja auch funktional und ich konnte damit eine XML mit Java transformieren. Ist XSL auch eine Skriptsprache?
XSL ist eine Progammiersprache, dass Templatematching-Techniken einsetzt und ist nicht funktional, sondern baut darauf auf (HIER).
 

Kababär

Top Contributor
Danke für deine ausführliche Antwort, Flown! Hat mir sehr geholfen :)
Irgendwie fehlt mir aber die Idee, wie ich so etwas schreiben kann, so dass es funktional ist.
Ich denke aber, dass es mit Scala am einfachsten gehen wird, weil es noch so viele "Hilfsfunktionen" wie "rechts/links-assioziativ", etc gibt und beide Paradigmen beherrscht.
Wir hatten vorher noch nie gelernt auf diese Ebene zu abstrahieren, so dass es etwas schwer ist, mich da zurechtzufinden.
Aber jetzt verstehe ich auf jeden Fall mal um einiges mehr.
Sind alle Methoden in Scala eigentlich static?
 

Kababär

Top Contributor
Wie kommst du zu diesem Schluss?
In einem Tutorial kam das so rüber, als ob alles static sein. Aber mittlerweile weiß ich, dass nicht alles static ist und man durchaus indiviuelle Objekte generieren kann.

Wenn du WIRKLICH funktionale Programmierung lernen willst, würde ich das auch mit einer Sprache tun, die dazu zwingt. zB. Haskell oder Scheme.
Auch wieder wahr, danke für den Hinweis.
 

Neue Themen


Oben