[Hinweis: Das Folgende ist in seiner Syntax und Konventionen etwas C # -lastig, z. B. das Zitieren von FxCop-Regeln, da dies mein Hintergrund ist. Die Absicht dieser Diskussion ist jedoch, sprachunabhängig zu sein, und die verwendeten Codebeispiele sollten allgemein als solche angesehen werden Pseudocode. - Mike]
Ich denke, wir sind uns alle einig, dass Klassen im Allgemeinen so gestaltet werden sollten, dass ihre Objektinstanzen unveränderlich sind, wo immer dies praktikabel ist, und dass die Ergebnisse des Aufrufs von Klassenmitgliedern so weit wie möglich frei von Nebenwirkungen sein sollten.
Historische Namenskonventionen verwenden jedoch in der Regel die aktive Stimme: "GetSomething", "DoSomehing" usw. Dies ist gut, da darin klar angegeben ist, welche Maßnahmen das Klassenmitglied ergreifen wird.
Ich fange jetzt jedoch an zu denken, dass Mitglieder manchmal (oder möglicherweise oft) davon profitieren könnten, wenn sie in der Vergangenheitsform benannt werden, um zu kennzeichnen, dass ein Wert zurückgegeben wird, ohne das referenzierte Objekt zu beeinflussen.
Für eine Methode, die ein Array transponiert, wird es in aktuellen Namensstilen wahrscheinlich als "Array.Transpose" bezeichnet. Wenn dieses Mitglied jedoch ein neues Array zurückgibt , ohne das referenzierte Objekt zu transponieren, wird es meiner Meinung nach als "Array.Transposed" bezeichnet 'wäre genauer und macht es dem Programmierer klarer.
Wenn Sie mit einer 'Array.Transpose ()' - Methode arbeiten, wird möglicherweise versehentlich versucht, Code wie den folgenden zu verwenden:
Array myArray = new Array();
myArray.Transpose();
Wenn die 'Transpose'-Methode jedoch ein neues Array zurückgibt, ohne das referenzierte Objekt zu beeinflussen, führt dieser Code nichts aus - das heißt,' myArray 'wird stillschweigend nicht transponiert. (Ich nehme an, wenn 'Transponieren' eine Eigenschaft wäre, würde der Compiler feststellen, dass das oben Genannte nicht legal ist, aber die FxCop-Richtlinien besagen, dass ein Mitglied, das eine Konvertierung durchführt, eine Methode sein sollte.)
Wenn die Methode jedoch in der Vergangenheitsform als "Array.Transposed" bezeichnet würde, wäre für den Benutzer klarer, dass die folgende Syntax erforderlich ist:
Array myArray = new Array();
Array transposedArray = myArray.Transposed();
Andere Namen, von denen ich denke, dass sie in diese Kategorie passen, sind Mitglieder mit den Namen "Größe geändert" vs. "Größe ändern", "Verschoben" vs. "Verschiebung" usw. Die Gegenwart wird für Mitglieder verwendet, die das referenzierte Objekt betreffen, während die Vergangenheitsform wird für Mitglieder verwendet, die einen neuen Wert zurückgegeben haben, ohne das referenzierte Objekt zu beeinflussen.
Ein anderer Ansatz, der derzeit üblicher ist, besteht darin, jedem Namen "Get" oder "To" voranzustellen, aber ich denke, dass dies unnötiges Gewicht hinzufügt, während der Wechsel in die Vergangenheitsform die Bedeutung effektiv kommuniziert.
Ist dies für andere Programmierer hier sinnvoll, oder klingt diese Vergangenheitsform beim Lesen zu umständlich?
Bearbeiten:
Tolle Diskussionen unten, ich danke allen vielmals. Einige Punkte, die ich basierend auf Ihren Kommentaren und meinen eigenen überarbeiteten Überlegungen dazu zusammenfassen möchte, folgen unten.
Methode zur Verkettung "fließender" Syntaxen
Basierend auf den folgenden Diskussionen ist die Verwendung der Vergangenheitsform wahrscheinlich von Wert, wenn sie für eine veränderbare Klasse verwendet wird, um zu verdeutlichen, welche Mitglieder den internen Status des referenzierten Objekts beeinflussen oder nicht.
Für unveränderliche Klassen, die die Mehrheit der Fälle sein sollten (man würde hoffen), denke ich jedoch, dass die Verwendung der Vergangenheitsform die Syntax unnötig umständlich machen kann.
Bei "fließenden Syntaxen", wie sie beispielsweise durch Methodenverkettung erstellt werden, würde die Verwendung der Vergangenheitsform den Code weniger lesbar machen. Wenn Sie beispielsweise LINQ über C # verwenden, kann eine typische Methodenkette wie folgt aussehen:
dataSource.Sort().Take(10).Select(x => x.ToString);
Wenn in die Vergangenheitsform geändert würde, würde dies unangenehm werden:
dataSource.Sorted().Taken(10).Selected(x => x.ToString);
Allerdings hat dataSource.Sorted () eine klarere Bedeutung als dataSource.Sort (), da LINQ-Ausdrücke immer eine neue Aufzählung erstellen, ohne die Quelle zu beeinflussen. Da wir uns dessen jedoch bei der Verwendung dieses Paradigmas voll bewusst sind, ist die Verwendung der Vergangenheitsform überflüssig und macht die "Fließfähigkeit" des Lesens umständlich, ohne dass ein wirklicher Gewinn erzielt wird.
Verwendung von Eigenschaften vs. Methoden
Ein zentrales Thema, das im Folgenden angesprochen wurde, betrifft die FxCop-Richtlinien für die Verwendung von "Get" -Methoden im Vergleich zu schreibgeschützten Eigenschaften. Beispiel: FxCop-Regel CA1024 .
Obwohl in dieser FxCop-Regel nicht explizit erwähnt, scheint die Verwendung von "To" -Methoden auch für diese Begründung zu gelten, da ToXXXXXX () -Methoden Konvertierungsmethoden sind. Im Fall von ToArray () ist die Methode sowohl eine Konvertierungsmethode als auch eine Methode, die ein Array zurückgibt.
Verwendung der Vergangenheitsform für boolesche Eigenschaften
Einige schlugen vor, dass die Vergangenheitsform einen booleschen Wert bedeuten kann, z. B. eine Eigenschaft 'Erfolgreich' oder 'Verbunden'. Ich glaube, dass die folgenden Retorten, in denen die Verwendung von 'Is', 'Has' oder 'Are' für boolesche Eigenschaften und Felder hervorgehoben wird, korrekt sind. Vergangenheitsform kann auch in dieser Hinsicht hilfreich sein, aber bei weitem nicht so viel wie die Verwendung eines 'Is'-Präfixes. Fühlen Sie sich frei, die Vergangenheitsform für boolesche Eigenschaften und Felder zu verwenden, es hilft, aber ich denke, dass es noch wichtiger ist, dem Namen 'Is', 'Has' oder 'Are' voranzustellen.
Allgemeine Schlussfolgerungen?
Für das Problem von Tranpose () vs. Transposed () denke ich, dass 'skizzy' es richtig gemacht hat, was darauf hindeutet, dass es Transpose () für eine mutierende Aktion vs. GetTransposed () für ein nicht mutierendes Ergebnis sein sollte. Dies macht es 100% klar. Aber ich denke auch hier, dass dies möglicherweise nur für eine veränderbare Klasse wie ein Array gilt.
Für unveränderliche Klassen, insbesondere wenn eine fließende Syntax zur Verkettung von Methoden verwendet werden könnte, würde diese Syntax meiner Meinung nach unnötig umständlich werden. Vergleichen Sie zum Beispiel:
var v = myObject.Transpose().Resize(3,5).Shift(2);
zu:
var v = myObject.GetTransposed().GetResized(3,5).GetShifted(2);
Hmmm ... eigentlich scheint es auch hier 100% klar zu sein, dass das Ergebnis die Quelle nicht beeinflusst, aber ich bin mir nicht sicher.
Ich denke, für ein Paradigma wie LINQ, bei dem es bekannt ist, ist die Verwendung von "Get" und / oder der Vergangenheitsform nicht erforderlich, aber für eine neue API könnte es einen gewissen Wert haben - zunächst! Wenn die API nur unveränderliche Objekte enthält, verringert die Verwendung von "Get" und / oder der Vergangenheitsform nur die Lesbarkeit, sobald der Benutzer dies versteht.
Ich denke, hier gibt es keine einfachen Antworten. Ich denke, man muss über die Gesamtheit Ihrer API nachdenken und sorgfältig auswählen!
-- Mike
Antworten:
Vergangenheitsform klingt irgendwie unangenehm. Ich denke, Sie wollten, dass das Wort ein Adjektiv ist.
Hier ist mein Vorschlag für das Problem, nach dem Sie gefragt haben:
Transpose()
Rufen Sie es stattdessen anGetTransposed()
. Auf diese Weise wissen Sie, dass Sie etwas empfangen und das Objekt nicht ändern.quelle
Transpose()
kann immer noch als Anpassen des gegebenen Objekts interpretiert werden. Vielleicht sollte dies ein Sprachkonstrukt sein. :)object.Transpose()
vsobject:Transpose()
.AsTransposed
eher alsGetTransposed
für Fälle, in denen aufeinanderfolgende wiederholte Anrufe ohne Nebenwirkungen zu semantisch identischen Ergebnissen führen (die möglicherweise dasselbe Objekt sind oder nicht, aber nicht als unterschiedliche Objekte gezeigt werden können, ohne Dinge wieReferenceEquals
oder das Äquivalent zu verwenden). .Es macht in der Tat Sinn.
Was Sie meinen, sollte meiner Meinung nach beim Entwerfen einer API oder einer Bibliothek als allgemeine Regel angesehen werden. Nur dann würde es einen greifbaren Vorteil bieten, wenn das System in allen Klassen konsistent ist.
Ein weiteres Problem ist, dass Benutzer der Schnittstellen in vielen Fällen nicht genau wissen, wie das Ergebnis erzielt wird.
Wird Transponieren () das aktuelle Objekt transponieren? Wird Transpose () eine neue transponierte Instanz erstellen und den Verweis darauf zurückgeben? Oder wird es vielleicht einmal transponiert, die Ergebnisse in einer Kopie zwischengespeichert und bei nachfolgenden Aufrufen zurückgegeben, ohne das aktuelle Objekt zu beeinflussen?
Benutzer möchten oft nur das transponierte Ergebnis erhalten, weshalb sich nicht viele für die von Ihnen vorgeschlagene Namenskonvention interessieren.
Aber für sich genommen ist es ein gültiger Vorschlag.
quelle
Ich bin absolut anderer Meinung. Vergangenheitsform ist umständlich und wird nicht häufig verwendet (was Grund genug ist, sie nicht zu bevorzugen).
Wenn die Methode das Objekt geändert hat, für das sie aufgerufen wurde, sollte sie sich nicht selbst zurückgeben. Dies macht deutlich, dass sie das Objekt ändert.
Wenn die Methode das aufgerufene Objekt nicht ändert und stattdessen ein neues Objekt erstellt, gibt die Methode ein Objekt desselben Typs zurück. Dies ist eine klare und bereits übliche Konvention.
Die Methodensignatur ist meiner Meinung nach eine klarere und viel häufiger verwendete Konvention, um anzugeben, ob die Methode ein neues Objekt zurückgibt oder den Angerufenen ändert.
quelle
Klingt vernünftig und es gibt Präzedenzfälle - Python hat beides
list.sort()
undsorted(seq)
. Die erste ist eine Methode, die andere ist eine Funktion, die auf jede iterierbare Methode einwirkt und eine Liste zurückgibt.quelle
In der Scala-Sammlungsbibliothek gibt es einige Methoden in der Vergangenheitsform:
grouped
Gibt einen Iterator zurück, der die Elemente einer Sequenz in Blöcken vonn
Elementen durchläuftsorted
Gibt eine sortierte Version der Sammlung zurückupdated
Gibt eine neue Version der Sammlung mit einem geänderten Element zurückAllerdings bin ich nicht sicher , ob dies eine bewusste Entscheidung oder ob sie einfach von Namen liefen, weil Scala Sammlung Bibliothek ist sehr reich. Zum Beispiel gibt es auch
groupBy
undsortBy
Methoden, und dieupdate
Methode ist speziell, weil der Compiler die Zuweisung neu schreibtin
Ältere Versionen von Scala in der Tat haben die Verwendung
update
für unveränderlich Sammlungen, aber mitupdate
einer neuen Version Rückkehr statt zu mutieren , ist sehr umständlich, weil man offensichtlich den Rückgabewert etwas zuweisen müssen, so zB „Aktualisierung“ ein Eintrag in einer unveränderlichen Karte wäre etwas , mögenJetzt ist es
In einer Sprache mit einem guten Typsystem sagen Ihnen die Typen normalerweise, ob die Routine ihre Argumente mutiert oder nicht. In Haskell zum Beispiel wäre der Typ der unveränderlichen Version so etwas wie
während eine veränderbare Version wäre
quelle
Wenn ich eine Methode / Eigenschaft in der übergebenen Zeit sehe, gehe ich sofort davon aus, dass sie einen Booleschen Wert zurückgibt. Ihr Vorschlag mag logisch sinnvoll sein, aber er scheint nur seltsam und umständlich. Wenn ich jemandem erklären muss, warum es Sinn macht, ist es wahrscheinlich keine gute Konvention.
quelle
Ich bin kein großer Fan von Variablennamen in der Vergangenheitsform für Unveränderlichkeit - es ist eine etwas ungewöhnliche Konvention und ich denke, sie würde Verwirrung stiften, insbesondere für Personen, die nicht besonders gut in englischer Grammatik sind (und ich mache nur einen halben Scherz) Dort...)
Diese Konventionen beseitigen auch die Möglichkeit, Vergangenheitsform zu verwenden, um etwas anderes zu bezeichnen, was ich für wichtiger halte: Eine Beschreibung des Zustands des beschriebenen Objekts, z. B. "verarbeitete Elemente", zeigt deutlich, dass die Elemente in einer Sammlung bereits vorhanden waren verarbeitet, was wichtige logische Informationen zu vermitteln ist.
Eine bessere Idee: alles unveränderlich machen . Dann brauchen Sie keine ausgefallene sprachliche Unterscheidung. Du willst es doch auch :-)
quelle