OK, der Titel ist ein bisschen knifflig, aber im Ernst, ich war auf einem Tell, frag eine Weile nicht nach Kick. Mir gefällt, wie es Methoden anregt, wirklich objektorientiert als Botschaften verwendet zu werden . Aber das hat ein quälendes Problem, das mir durch den Kopf ging.
Ich habe den Verdacht, dass gut geschriebener Code gleichzeitig OO-Prinzipien und Funktionsprinzipien folgen kann. Ich versuche, diese Ideen in Einklang zu bringen, und der große Knackpunkt, auf den ich gestoßen bin, ist return
.
Eine reine Funktion hat zwei Eigenschaften:
Ein wiederholter Aufruf mit denselben Eingaben führt immer zum selben Ergebnis. Dies impliziert, dass es unveränderlich ist. Sein Zustand wird nur einmal gesetzt.
Es entstehen keine Nebenwirkungen. Die einzige durch den Aufruf verursachte Änderung ist das Erzeugen des Ergebnisses.
Wie kann man also rein funktional sein, wenn man darauf verzichtet, return
Ergebnisse zu kommunizieren?
Die Tell-Don't-Ask- Idee funktioniert unter Verwendung dessen, was einige als Nebenwirkung betrachten würden. Wenn ich mich mit einem Objekt befasse, frage ich es nicht nach seinem internen Zustand. Ich sage ihm, was ich tun muss, und er verwendet seinen internen Zustand, um herauszufinden, was mit dem zu tun ist, was ich ihm gesagt habe. Sobald ich es erzähle, frage ich nicht, was es getan hat. Ich erwarte nur, dass es etwas getan hat, was ihm befohlen wurde.
Ich denke an Tell, Ask nicht mehr als nur einen anderen Namen für die Verkapselung. Wenn ich benutze, habe return
ich keine Ahnung, wie ich genannt wurde. Ich kann nicht sagen, dass es sich um ein Protokoll handelt, ich muss es erzwingen, um mit meinem Protokoll fertig zu werden. Was in vielen Fällen als interner Zustand ausgedrückt wird. Auch wenn das, was belichtet wird, nicht genau der Status ist, handelt es sich in der Regel nur um eine Berechnung, die für Status- und Eingabeargumente ausgeführt wird. Eine Schnittstelle zu haben, über die man reagieren kann, bietet die Möglichkeit, die Ergebnisse in einen aussagekräftigeren Zustand als interne Zustände oder Berechnungen zu überführen. Das ist die Weitergabe von Nachrichten . Siehe dieses Beispiel .
Vor langer Zeit, als Festplatten tatsächlich Festplatten enthielten und ein USB-Stick das war, was Sie im Auto taten, als das Rad zu kalt war, um es mit den Fingern zu berühren, wurde mir beigebracht, wie nervig Menschen Funktionen betrachten, die über Parameter verfügen. void swap(int *first, int *second)
schien so praktisch, aber wir wurden ermutigt, Funktionen zu schreiben, die die Ergebnisse zurückgaben. Also nahm ich mir den Glauben zu Herzen und fing an, ihm zu folgen.
Aber jetzt sehe ich Leute, die Architekturen bauen, in denen Objekte ihre Konstruktionsweise kontrollieren lassen, wohin sie ihre Ergebnisse senden. Hier ist eine Beispielimplementierung . Das Injizieren des Output-Port-Objekts scheint wieder ein bisschen wie die Out-Parameter-Idee zu sein. Aber so sagen Sie anderen Objekten, was sie getan haben.
Als ich zum ersten Mal etwas über Nebenwirkungen erfuhr, stellte ich mir das als Ausgabeparameter vor. Wir sollten die Leute nicht überraschen, indem wir einen Teil der Arbeit auf überraschende Weise erledigen, dh indem wir uns nicht an die return result
Konvention halten. Nun sicher, ich weiß, dass es eine Menge paralleler asynchroner Threading-Probleme gibt, mit denen sich die Nebenwirkungen herumschlagen, aber Return ist eigentlich nur eine Konvention, bei der Sie das Ergebnis auf dem Stapel belassen, damit Sie es später entfernen können. Das ist alles was es wirklich ist.
Was ich wirklich zu fragen versuche:
Ist return
die einzige Möglichkeit, all diese Nebenwirkungen zu vermeiden und die Sicherheit des Fadens ohne Sperren usw. zu gewährleisten ? Oder kann ich sagen, nicht auf rein funktionale Weise fragen ?