Namenskonvention für Funktionen, die Nebenwirkungen haben? [geschlossen]


9

Ich hörte jemanden sagen, dass seine Sprache eine Konvention hat, bei der die Namen von Funktionen, die den Zustand mutieren, mit einem Ausrufezeichen enden müssen. Ich versuche, mehr Funktionscode zu schreiben, und ich mag die Idee, Funktionen irgendwie nach ihrem Nebenwirkungsstatus zu markieren, dh keine, innere Nebenwirkungen, äußere Nebenwirkungen (ich kenne die richtige fp-Terminologie nicht, aber Sie haben die Idee, dass ich Hoffnung).

Natürlich fällt es mir leicht, ein eigenes Namensschema zu entwickeln, aber ich habe mich gefragt, ob solche Schemata / Konventionen bereits existieren, bevor ich eines selbst backe.

edit: Danke für all die Antworten, genau das war es, wonach ich gesucht habe und ich fand sie alle wirklich nützlich. Ich hätte wahrscheinlich erwähnen sollen, dass ich ein altes Javascript umgestalte, damit statisch typisierte Sprachen möglicherweise einen Unterschied zwischen Code mit und ohne Nebenwirkungen erzwingen können. Ich muss mich jedoch auf eine selbst auferlegte Namenskonvention verlassen.

edit2: Was die Mods betrifft, die dies als primär meinungsbasiert schließen, muss ich nicht zustimmen. Ich habe gefragt, welche Konventionen, wenn überhaupt, allgemein verwendet werden - dies ist nach jedermanns Definition eine Tatsachenfrage, keine Meinung!


1
Dies variiert wahrscheinlich zwischen den Sprachen und ist wahrscheinlich sehr meinungsorientiert.
David Arno

1
Die Konvention von Scala besteht beispielsweise darin, Methoden ohne Klammern zu deklarieren (ähnlich wie Eigenschaften), sofern sie keine Nebenwirkungen haben. Aber Sie können dies nicht in einer anderen Sprache verwenden, die ich kenne. Das Ausrufezeichen erscheint mir schrecklich; Es gibt zu viele andere Verwendungszwecke für dieses Symbol, und ich würde feststellen, dass es verwendet wird, um ablenkende Methoden zu markieren.
Robert Harvey

2
@RobertHarvey Ich glaube, Scheme ist eine Sprache, die diese Konvention verwendet, und die Konvention existiert, weil der Operator zum Mutieren des Status einer Variablen ist !(es wäre syntaktisch nicht gültig, den Status einer Variablen ohne diesen Operator zu mutieren, wenn Speicher dient ), also ist es tatsächlich eine ziemlich vernünftige Konvention in dieser Sprache .
Servy

3
@Servy Standard Scheme hat set!zum Mutieren einer Variablen, aber keinen eigenständigen !Operator. Die Konvention existiert, weil Lisp in der Vergangenheit Symbole in Bezeichnern verwendet hat, um Bedeutung zu vermitteln, da nur sehr wenige Einschränkungen hinsichtlich der Gültigkeit eines gültigen Bezeichners bestehen. Das Fehlen von Einschränkungen besteht darin, dass sich Lisp auf Makros und domänenspezifische Sprachen konzentriert.
Jack

1
Ruby verwendet auch die !Konvention (z. B. für downcaseund downcase!), zeigt jedoch allgemeiner "Gefahr" als "Nebenwirkungen" an.
Andrew

Antworten:


8

Folgen Sie der Befehl-Abfrage-Trennung . Funktionen, die Werte zurückgeben, haben keine Nebenwirkungen, Funktionen, die Nebenwirkungen haben, geben keine Werte zurück.

Es hilft auch, Funktionen zu benennen, die Werte nach dem zurückgegebenen Objekt zurückgeben, dh nach einem Substantiv oder Adjektiv. Während Funktionen, die Nebenwirkungen haben, nach dem Effekt benannt werden sollten, den sie ausführen, dh nach einem Verb.

So hat zum Beispiel myArray.sort()ein Nebeneffekt, es sortiert das Array. Daher gibt es nichts zurück und ist nach einem Verb benannt. In der Zwischenzeit wird myArray.sorted()eine sortierte Kopie von zurückgegeben myArray. Daher hat es keine Nebenwirkungen und ist nach dem zurückgegebenen Objekt benannt.

Zu Ihrer Information, die obige Idee (Substantive / Adjektive für reine Funktionen und Verben für Nebenwirkungen erzeugende Funktionen) ist ein Standard in Swift 3.

Benennen Sie Funktionen und Methoden nach ihren Nebenwirkungen

  • Diejenigen ohne Nebenwirkungen sollten als Nominalphrasen gelesen werden.
  • Diejenigen mit Nebenwirkungen sollten als zwingende Verbalphrasen gelesen werden.

( https://swift.org/documentation/api-design-guidelines/#strive-for-fluent-usage )


4

Das grundlegende Problem besteht darin, dass Nebenwirkungen im Typsystem nicht erfasst werden. Die Verwendung einer Funktionsbenennungskonvention ist ein schlechter Ersatz für die statische Überprüfung. Es gibt einige Möglichkeiten, dies zu umgehen.

Haskell verwendet Monaden, um Nebenwirkungen in einem Kontext zu erfassen. Die monadische bindOperation setzt unreine Funktionen zusammen, so wie der normale Funktionszusammensetzungsoperator reine Funktionen zusammensetzt. Die Monadengesetze stellen sicher, dass dieser Operator analog zur regulären Komposition handelt.

Eine andere Möglichkeit besteht darin, reine von unreinen zu trennen, indem Ausdrücke vollständig von Befehlen getrennt werden . Dies sind zwei völlig unterschiedliche syntaktische Kategorien, die nicht gemischt werden können. Ausdrücke haben Typen, mit denen wir Begriffe verfassen können. Ein Ausdruck kann per Definition nicht von zuweisbaren Elementen abhängen (er hat keinen Zugriff auf den Speicher ). Befehle haben keinen Typ im herkömmlichen Sinne und können keinen Wert zurückgeben. Sie können nur mit dem Programm interagieren, indem sie den Speicher mutieren.

Beachten Sie, dass herkömmlich typsichere "funktionale" Sprachen möglicherweise keinem dieser Paradigmen folgen. Zum Beispiel unterscheiden OCaml und SML reine von unreinen Funktionen nicht richtig.

Keine dieser Lösungen ist perfekt, und dies ist immer noch ein aktives Forschungsgebiet.


Beachten Sie, dass haskell auch unsafePerformIO
jk hat.

Ich bin mit Haskell nicht sehr vertraut. Die meisten sicheren Sprachen bieten eine Möglichkeit, das Typensystem als letzten Ausweg zu untergraben. Außerdem macht es Ihr Benutzername mir schwer, alles, was Sie sagen, ernst zu nehmen: D
Gardenhead

@jk unsafePerformIO kann in diesem Zusammenhang sicher ignoriert werden. Es handelt sich um eine Notluke, die nicht für den normalen Code vorgesehen ist, und enthält erhebliche Einschränkungen und Warnungen . Es darf sowieso nicht mit nebenwirkendem Code verwendet werden.
Andres F.

@AndresF. Mein Punkt war, dass unsicher * eine Namenskonvention für gut unsichere Dinge in Haskell ist, was so ziemlich Dinge bedeutet, die selbst Nebenwirkungen haben, obwohl sie auch nur von der Implementierung selbst verwendet werden, nicht vom Benutzercode
jk.

3

Das Aufrufen von Methoden oder Funktionen scheint eine fantastische Idee zu sein, da dies dazu beitragen kann, Zeiten auszuspülen, in denen Code ein gewisses Maß an Unsicherheit einführt. Joel Spolsky befasst sich in seinem Artikel "Falschen Code falsch aussehen lassen" ( http://www.joelonsoftware.com/articles/Wrong.html ) ausführlich mit dieser Idee, in dem er die Verwendung einer weniger bekannten Version der ungarischen Notation empfiehlt bestimmte Ideen innerhalb des Systems transparenter.

Die Sprache, auf die Sie sich beziehen, ist mit ziemlicher Sicherheit Schema ( ein einfaches Beispiel finden Sie unter http://download.plt-scheme.org/doc/html/guide/set_.html ). Mir ist nichts Globales bekannt.

Java stellt Eigenschaftsmethoden diesen Zweck vor getund seterfüllt ihn teilweise, aber mir sind keine gängigen Konventionen der Art bekannt, die Sie außerhalb der Lisp-Welt erwähnen und die nicht (wie @gardenhead hervorhob) in das Typsystem eingebettet sind.

Ich denke, im Wesentlichen sind Sie ziemlich sicher, eine Stilrichtlinie für Ihr Team zu erstellen, insbesondere wenn Sie sich mit etwas befassen, das viel Parallelität aufweist und bei dem Nebenwirkungen noch gefährlicher sind als gewöhnlich.

Was auch immer es wert ist, ich kann mir ein paar Möglichkeiten vorstellen, dies in ALGOL-ähnlichen Sprachen zu implementieren. Ein einfaches könnte ein Präfix sein, wie es von Spolsky quasi vorgeschlagen wurde - etwa s_für zustandsbehaftete Operationen und l_für staatenlose Operationen.

Eine modernere Idee könnte darin bestehen, Wörter als Präfixe oder Suffixe zu setzen. Vielleicht calculateist eine reine Funktion, aber mutateCalculationdie unreine.

Schließlich gibt es einen Grad, in dem ein Großteil davon durch Trennung von Bedenken behandelt werden sollte - nur die Schicht, die die Datenbank aktualisiert, sollte beispielsweise in der Lage sein, die Datenbank zu aktualisieren. In diesem Fall ist es ziemlich offensichtlich, dass Sie sich über Nebenwirkungen in zustandsbehafteten Schichten Gedanken machen müssen.


Danke für die Antwort. Ich stimme zu, dass dies in einer idealen Welt hauptsächlich durch Trennung von Bedenken gehandhabt werden sollte. Mein Hauptanwendungsfall für eine Namenskonvention ist das Auseinandernehmen und Umgestalten von altem Code, der nicht unbedingt mit Blick auf Eleganz und Best Practices geschrieben wurde! (Vielleicht manchmal alleine am Tag bevor ich Religion bekam!)
Technicalbloke

Oh und dieser Artikel von Joel Spolsky ist fantastisch, danke für den Link!
Technicalbloke
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.