Xin hat geschrieben:Was mir gerade mal durch den Kopf ging...
Aus deinem Speicher für ruhige Zeiten im Forum?
Lambda-Funktionen dienen doch dazu, eine (Call-Back-)Funktion direkt als Parameter zu übergeben, so dass man nicht erst eine neue Funktion schreiben muss und den Namen der Funktion übergeben muss.
Anders formuliert baut man die zu übergebende Funktion in den Algorithmus ein, der den Funktionsaufruf auf eine Funktion enthält, die eine Call-Back-Funktion als Parameter benötigt.
Damit vermüllt man doch prinzipiell den Algorithmus, in dem dann mittendrin eine vollkommen andere Funktion steht, die für diesen Algorithmus als Call-Back-Funktion benötigt wird.
Ich glaube du benutzt den Begriff "Callback"-Funktion etwas zu traditionell. Es stimmt schon, es kann dafür verwendet werden klassische "Callbacks" zu implementieren mit Funktionszeigern für Datenauswertung ("so, hier haste deine Daten") oder Statusmeldungen ("Ich wär dann fertig.").
Wenn du dir aber die tatsächlichen ausdrücke in denen Lambdas vorkommen ansehe, z.B. in dem von
dieser Webseite schamlos geklauten Code:
Code: Alles auswählen
#include <algorithm>
#include <deque>
#include <iostream>
#include <iterator>
#include <ostream>
#include <vector>
using namespace std;
int main() {
vector<int> v;
for (int i = 0; i < 10; ++i) {
v.push_back(i);
}
deque<int> d;
transform(v.begin(), v.end(), front_inserter(d), [](int n) { return n * n * n; });
for_each(d.begin(), d.end(), [](int n) { cout << n << " "; });
cout << endl;
}
Dann ist das Lambda nicht einfach irgendein zufälliger Callback, den man in den Algorithmus reingezwungen hat, sonder er _ist_ der Algorithmus. Das Lambda ist hier eben kein Callback mehr, sondern teil des Codes. Auch auf Maschinenebene: Wenn ich das gleiche in C machen will, brauche ich einen Funktionszeiger. Um einen Funktionszeiger zu erhalten muss die Funktion tatsächlich existieren, und jedes mal wenn der Code gebraucht wird, muss tatsächlich der Maschinencode den aufruf machen (push argument1, push argument2, call XXX, push ebp, mov eax, [esp-8], blabla..., pop ebp, ret).
DAS ist ein echter Callback. Ich bin mir ziemlich sicher, ein Lambda mit vernünftig eingestelltem Compiler kompiliert wird sofort ge-inlined, und der Code steht auch _im_ algorithmus, und gehört dann auch dazu.
Das steht doch im krassen Widerspruch zur Argumentation von Exceptions, die ihren Wert daraus ziehen, dass sie die Fehlerbehandlung aus dem Algorithmus herausziehen, so dass der Algorithmus leicht zu lesen sei.
Versteh ich nicht. Wieso steht das im Widerspruch?
Laufen da nicht irgendwie zwei Hypes mit ihren Philosophien frontal gegeneinander?
Hypes hin oder her, es ist ein Sprachfeature, und dazu ein verdammt nützliches. Früher musste man der STL ganze Funktionsobjekte füttern mit class {} und public operator() (). Das ist eine verkürzte Syntax, und die kann von mir aus gehypt sein oder nicht, ich werde sie verwenden. Um ehrlich zu sein, wer genau hypt denn Sprachfeatures?
Wie kann es gut sein, Algorithmen von Call-Back-Funktionen mitten in den Haupt-Algorithmus zu schrieben, während man gleichzeitig die Fehlerbehandlung des Haupt-Algorithmus aus dem Haupt-Algorithmus herauszieht.
Wie gesagt, ich glaube du siehst hier den Begriff "Callback" zu eng.
Denken wir das zu Ende: Steht jetzt nicht die Exceptionbehandlung einer Callback-Funktion zusammen mit der Definition der Call-Back-Funktion inmitten des Hauptalgorithmus', welcher zuvor mühevoll von eigenen Fehlerbehandlung befreit wurde?
Beides ist State of the Art in der Programmierung?
Wer sagt denn, dass ich meine Exceptions innerhalb des Algorithmus abfangen will? Ich kann meinen catch-block genauso um den ganzen Funktionsaufruf legen.
Was mich interessieren würde, was genau verstehst du unter Fehlerbehandlung? Was stellst du dir da vor? Welche Fehler werden behandelt? Wie reagierst du darauf? Willst du z.B. std::bad_cast's auffangen? Oder std::bad_alloc's?
Was mir gerade auffällt: wie sähe denn das ohne Exceptions aus? Hier kommt die Fehlerbehandlung genauso in den Code. Da wird der Algorithmus ja noch dicker! Wenn ich in jeder Iteration abfragen muss ob eh noch alles grün ist, dann ist das auch nicht viel besser.
Ich bin an Meinungen interessiert - an prinzipiellen Meinungen, nicht an Meinungen mit Fallunterscheidungen, wie "Lambda toll, wenn maximal drei Zeilen" oder "Exeptions toll, wenn kein Catch-All..."
Wieso denn kein Fallunterscheidungen? Das ist ja die Realität - man kann sich mit ziemlich vielemen ins Bein schießen. Muss man aber nicht. Zu sagen "Lambdas sind generell Falsch" weils Leute gibt die dort ganze Funktionen reinpacken empfinde ich als hirnrissig.
Es gibt einfach keine "prinzipielle" Antwort auf jede Frage, und die Antwort wird immer vom betrachteten Fall abhängig sein. Alles andere ist akademische Informatik und gehört in den Hörsaal, aber nicht in Code.
, das giben Programmiersprachen nämlich soweit mir bekannt ist nicht her. Was nicht unterbunden wird, wird auch gemacht.
Dann sag ich: von mir aus, dann macht doch einfach! Schreibt euren queeren Code, wenn ihr meint dass es richtig ist. Ich halte mich an die Regeln der vernunft, und bewege auch meine Mitarbeiter oder mitprogrammierer dazu sich an die Regeln der Vernunft zu halten.
Was ich generell noch zu C++ sagen will: es macht Code einfach lesbarer. Es macht Code lebendiger, es macht (meistens) weniger Syntax und mehr Semantik. Man kann schreiben was man im Kopf hat, und da sind Lambdas ein klassisches Beispiel dafür: Wenn ich std::accumulate() sagen will, wie es seine elemente zu Addieren hat, will ich nciht extra eine neue Klasse anlegen müssen. Ich will IN DIESER ZEILE sagen können was ich will.
Ich hatte letzte Woche das Vergnügen Java programmieren zu dürfen. Da sind dann ausdrücke herausgekommen wie:
CommandRunner cr = IntegrationPointFactory.getInstance().createIntegrationPoint().createSession().createCommandRunner();
Super. Glatte 1 für das Verständnis des Begriffes "Objektorientierte Programmierung". Und wieso der ganze Spaß? Weil die netten Java leute gemeint haben, Operatorüberladung ist zu kompliziert für den Programmierer, den Code versteht man ja nicht. Und Mehrfachvererbung ist auch zu kompliziert, da kann man ja auch was falsch machen. Und Templates streichen wir auch, da kann man sich ja richtig ins Bein schießen. Geht ja gar nicht.
Und was ist rausgekommen? Eine Syntaktische wüste. Monokultur, die den Code unglaublich Zäh und langweilig und furchtbar "Verbose"
(kein passendes deutsches Wort im Kopf) machen. Und so wie ich das sehe genau aus der Argumentation heraus, dass manche Programmierer es falsch verwenden könnten.
Haters gonna hate, potatoes gonna potate.