Hallo Hufeisen,
prozedurale Programmierung, funktionale Programmierung und objektiorientierte Programmierung sind drei verschiedene Programmierparadigmen, man kann statt Paradigma vielleicht auch Grundhaltungen oder Gedankensysteme sagen. Eine exakte Definition und genaue Abgrenzung sind dabei nicht immer möglich. Typische Vertreter prozeduraler Programmiersprachen sind Assembler und C, typische Vertreter funktionaler Programmiersprachen sind LISP, Haskell und Erlang und typische Vertreter objektiorientierten Programmierens sind SmallTalk und Java. Früher waren prozedurale am nächsten am Metall und haben daher auf ressourcenschwachen Rechnern brilliert, dann wurden die Rechner immer leistungsstärker und die Programme immer größer und dann dominierten die objektorientierten Sprachen und jetzt, mit dem Trend zu vielen Kernen, besinnt man sich wieder mehr auf die funktionalen.
Dabei entstehen Mischsprachen, die einen Mischmasch aus allem umfassen. R ist ein gutes Beispiel, wo man einer ursprünglich prozedural und begrenzt auch funktionalen Sprache später drei verschiedene Objektsysteme aufgepresst hat und alles irgendwie durcheinander verwendet.
Beim prozeduralen Programmieren erklärt man dem Computer die Prozedur:
ich sage, dass er mit i eine Laufzeitvariable bereithalten soll, welches Kriterium dem Abbruch dient. Ich definiere, ob die Laufzeitvariable von 0 bis 9 oder von 1 bis 10 läuft, obwohl das für das Ergebnis gar keinen Unterschied mach. Ich muss dabei sehr aufpassen, ob ich jetzt wirklich zehn oder neu oder elfmal was printe aber dafür ist das leicht in Maschinencode zu übersetzen.
Die funktionale Variante wäre
Im Idealfall sage ich dem Computer, was er machen soll und nicht, wie er es machen soll. Ob es eine Laufzeitvarialbe gibt und von wo nach wo die läuft, das passiert alles im Hintergrund. Das macht alles eine Funktion. Ich kann einer Funktion eine Funktion als Argument übergeben. Im Idealfall nimmt eine Funktion Daten als Argument an und gibt sie als Rückgabewert zurück. print gibt etwas auf den Bildschirm aus und verändert damit etwas jenseits seines Rückgabewerts. Bei Funktional-Hartlinern wird das schon als wesentliches Problem angesehen. Wenn ich nämlich den o. g. Code in 50 Threads parallel laufen lasse ist nicht definiert, in welcher Reihenfolge etwas ausgegeben wird, weil man ja nicht weiß, welcher Thread schneller und welcher langsamer läuft. In strengen funktionalen Sprachen wie Haskell ist
i <- i + 1 unmöglich, weil eine Variable ihren einmal festgelegten Wert nicht ändern kann. Deshalb gibt es auch keine Schleifen mit Laufvariablen und man muss alles, was man in anderen Sprachen mit Schleifen macht mit echter Rekursion machen.
Objektorientiert wäre so etwas in der Art wie
Das Objekt "Hallo" bringt seine eigenen Methoden mit, so was ähnliches wie Funktionen, die man auf dieses Objekt anwenden kann. Hier etwa eine Methode, die etwas 10 Mal ausgibt. Die Methode gehört zur Klasse und ein Objekt gehört immer mindestens einer Klasse an. Man kann sich vorstellen, dass bei einem riesigen Softwareprojekt ein Programmierer allein die Klasse "String" beschreibt. Er muss dafür sorgen, dass die printTimes-Methode funktioniert, alle anderen müssen nur wissen, dass "Hallo" eine Instanz der String-Klasse ist und dass die String-Klasse ein printTimes-Methode hat. Sie müssen sich darum keine Gedanken machen, deshalb können auch sehr umfangreiche Programme in großen Teams erstellt werden, weil die Veränderung in einer Klasse allen anderen egal sein kann, solange die Schnittstelle / Methoden definiert bleiben.
Das alles hat immer Vor- und Nachteile und deshalb kann man sich da herzlich die Köpfe einschlagen oder sich eklestizistisch immer das heraussuchen, was man will.
Wenn EDi so funktionell programmiert, dass er alles parallelisieren kann, dann darf in seinen Funktionen eben auch kein print vorkommen. Man erkauft oft das eine durch das andere.
Wie gesagt, ist die Grenzziehung nur für Hardliner exakt. Sprachen, die alles können (R, Scala, neueste Java-Version) sind sehr mächtig, werden dafür aber auch sehr komplex. In LISP kannst Du nicht "
1 + 1" schreiben, weil der Name der Funktion immer vorne steht, also "
(+ 1 1)". Klingt lästig, aber dabei kann es nie zu Fragen kommen, ob jetzt Punkt- oder Strichrechnung zuerst geht. Der typische R-Fehler "
1:n+1" kann überhaupt nicht vorkommen und man ist stolz, dass die vollständige Syntax der Sprache auf eine Tafel passt und in 10 Minuten vollständig erklärt werden kann. Es hat halt immer alles zwei Seiten.
LG,
Bernhard