Was ist der Unterschied zwischen den Namenspräfixen "to" und "as"? [geschlossen]

78

Was ist der Unterschied zwischen „zu“ und „als“ Methode Namenspräfixe wie

  • auflisten(),
  • asList (),
  • usw...

Wann welche beim Entwerfen einer Methode verwenden?

Daniel Hári
quelle

Antworten:

120

Von einer toXYZ()Funktion wird erwartet, dass sie eine Konvertierung durchführt und ein neues unabhängiges Objekt java.lang.String.toString()zurückgibt (obwohl die Unveränderlichkeit eine Optimierung ermöglicht, gibt sie nur das Objekt zurück).
Als Beispiel haben wir in C ++ ein Programm, std::bitset::to_ulong()das leicht versagen kann, und eine ganze Fülle von Funktionen to_string(), die eine (mehr oder weniger) komplexe Konvertierung durchführen und Speicher zuweisen.

Von einer asXYZ()Funktion wird hingegen erwartet, dass sie eine (möglicherweise andere) Ansicht der Quelle zurückgibt und nur minimale Arbeit leistet.
Als Beispiel haben wir in C ++, std::as_const()das gerade eine konstante Referenz zurückgibt, und das kompliziertere, std::forward_as_tupledas auch auf seine Argumente durch Referenz verweist.

Deduplizierer
quelle
19
Es stellt sich heraus, dass es dafür einen Präzedenzfall gibt. Im Allgemeinen ähnelt As [etwas] einer Besetzung, wohingegen To [etwas] ein neues Objekt (eines anderen Typs) als ein vorhandenes erstellt. Im Fall von ToList wird es O (n) sein und mit ziemlicher Sicherheit teurer als ein "As". Siehe stackoverflow.com/questions/17968469/…
Robert Harvey
5
Dies ist Teil der Auswahl beschreibender Namen, und selbst wenn diese spezielle Unterscheidung im Kodierungsstandard nicht kodiert ist, verstößt ein Verstoß gegen das Prinzip des geringsten Erstaunens .
Deduplicator
11
Ich würde es so beschreiben, als würde ich instinktiv von "zu" als "ändern zu" und "als" als "behandeln als" denken. Ersteres impliziert, dass man daran arbeitet, das Ding zu verändern, letzteres impliziert, dass es nur ein Unterschied ist, wie man damit arbeitet.
Latty
6
Wenn es etwas bedeutet, sollte es dies bedeuten. Ich würde vorschlagen, dass es oft nichts bedeutet, also würde ich mich nicht auf zufälligen Code von Drittanbietern verlassen (ohne etwas in den Dokumenten zu sehen). Es wäre jedoch eine gute Konvention, einen Code zu übernehmen.
Ben
4
Diese Antwort ist auch in C ++ korrekt: Erstellt beispielsweise std::to_string(x)ein neues Zeichenfolgenobjekt, std::as_const(x)erstellt jedoch eine Referenz (eine Ansicht) des vorhandenen Objekts.
Quuxplusone
13

Ehrlich gesagt kann es nur Inkonsistenz benennen. Wenn Blick auf Standard - Bibliotheksobjekte in Smalltalk, zum Beispiel, alle Methoden , die „komplexe Konvertierungen“ oder „Rückkehr einfache Darstellungen in einer anderen Art“ sind mit dem Präfix tun as, wie in asString, asFloat, asSeconds, und die Standard - Methode für etwas auf etwas anderen Umwandlung as: aClass.

In Ruby werden die gleichen Arten von Verfahren mit dem Präfix to_, wie in to_s, to_a, to_h, kurz für string, arrayund hashjeweils.

Keine der Standardbibliotheken scheint zwischen verschiedenen Arten von Konvertierungen zu unterscheiden, wahrscheinlich, weil dies als Implementierungsdetail angesehen werden sollte.

In Java gibt es jedoch viele Verwechslungen. Wie Sie erwähnt haben , ist es toString, asListund so weiter. Ich glaube, dass dies nur eine Namensinkonsistenz ist, denn wenn Sie versuchen, für jedes Präfix eine andere Bedeutung zu definieren, finden Sie immer ein Gegenbeispiel an einer anderen Stelle in der Standardbibliothek.

In jedem Fall ist es für Sie und Ihr Team wichtig, ein Präfix auszuwählen und es im gesamten Code einheitlich zu verwenden. Konsistenz ist der Schlüssel, damit sich die Menschen nicht wundern müssen, wie Sie es mussten.

MichelHenrich
quelle
1
Ich glaube nicht daran, einen Stil für ein ganzes Team auszuwählen, sondern einen Stil für ähnliche Fälle in einem Modul, konsequent.
Daniel Hári
12
Erstellt in Java toStringeine neue Zeichenfolge, die vollständig vom Objekt getrennt ist (und aufgrund der Unveränderlichkeit gibt es keine andere Möglichkeit). Das gleiche gilt zB für Collection#toArray, während Arrays#asListeine Ansicht des Arrays zurückgegeben wird, das bidirektional verbunden ist (das Mutieren des Arrays ändert die Liste und umgekehrt). Es ist also ziemlich konsistent, obwohl es Ausnahmen geben kann. Ein Präfix zu wählen wäre falsch. Wenn ja Arrays#toList, würde ich erwarten, dass eine neue Liste mit einem neuen zugrunde liegenden Array erstellt wird.
Maaartinus
Ich denke, Smalltalk hat gerade einen Fehler gemacht, sie haben die Konvention nicht verstanden. Es ist schwierig, Konventionen zu verstehen (und sogar zu bemerken), weil sie so abstrakt und nicht besonders wirkungsvoll sind. Schon das Stellen dieser Frage erfordert einige Einsichten.
USR
3
@usr Smalltalk könnte entworfen worden sein, bevor es zu einer Convention wurde
Bergi
6

Während es bereits eine akzeptierte Antwort gibt, scheint sie sich auf C ++ zu konzentrieren, während die Frage mit Java markiert ist . In Java ist Arrays.asList das erste Beispiel, das für diese Art von Dingen in den Sinn kommt. Es gibt im Wesentlichen eine Ansicht eines Arrays zurück, das in eine Liste eingeschlossen ist. Das zugrunde liegende Array und die Liste sind jedoch weiterhin verbunden. Änderungen am Array werden in der Liste angezeigt und umgekehrt. Das von der Methode toArray der Liste zurückgegebene Array ist jedoch unabhängig vom ursprünglichen Array und von der Liste:

String[] wordArray = {"one", "fine", "day"};
List<String> wordList = Arrays.asList(wordArray);

// changes to the array are visible in the list
System.out.println(wordList); // prints "[one, fine, day]"
wordArray[1] = "horrible";
System.out.println(wordList); // prints "[one, horrible, day]"

// changes to the list are visible in the array
wordList.set(1, "beautiful");
System.out.println(wordArray[1]); // prints "beautiful"

// but changes to the list or array don't affect the 
// result from the list's toArray method.
String[] moreWords = wordList.toArray(new String[] {});
wordList.set(0, "the");
wordArray[1] = "best";
for (int i=0; i<3; i++) {
  System.out.println(moreWords[i]); // prints "one", "beautiful", and "day"
}

Trotzdem gibt es keine Garantie dafür, dass jeder Bibliotheksentwickler diese Konvention befolgt. Sie müssen daher weiterhin in der Dokumentation nachsehen, ob dies das Verhalten ist, das Sie von unbekanntem Code erhalten.

Die andere Stelle, die ich als ... () - Methoden angesehen habe, ist das Downcasting von Typen zu Untertypen. Wenn Sie beispielsweise eine Reihe von Untertypen aufgelistet haben, erhalten Sie möglicherweise folgenden Code:

  /**
   * Every Node is either an ANode or a BNode.
   */
  interface Node {

    /**
     * Returns this Node as an ANode.
     * 
     * @return this node
     */
    default ANode asANode() {
      if (this instanceof ANode) {
        return (ANode) this;
      }
      else {
        throw new UnsupportedOperationException();
      }
      // Or, in Java8 style, perhaps:
      // return Optional.of(this)
      //     .filter(ANode.class::isInstance)
      //     .map(ANode.class::cast)
      //     .orElseThrow(UnsupportedOperationException::new);
    }

    /**
     * Returns this Node as a BNode.
     * 
     * @return this node
     */
    default BNode asBNode() {
      if (this instanceof BNode) {
        return (BNode) this;
      }
      else {
        throw new UnsupportedOperationException();
      }
    }
  }
Joshua Taylor
quelle
1

Der Unterschied, den ich bemerkte (gerade als ich darüber nachdachte), ist

  • So konvertieren Sie normalerweise in einen anderen Referenztyp (ein etwas komplexes Objekt)
  • Gibt normalerweise einen einfachen Werttyp zurück

Wir sehen also AsInteger und AsString und wir sehen ToArray und ToStringList.

Konversion implizieren, was Sinn macht (es ist eine Bewegung, ein Prozess). Wie impliziert eine Darstellung, eine Art, das ursprüngliche Objekt auszudrücken.

Eine andere Betrachtungsweise:

  • To ist eine Operation, daher würden Sie sie für Methoden verwenden.
  • Da es sich um eine einfache Darstellung handelt, würden Sie sie für Eigenschaften verwenden.

Und dann gibt es "Stand der Technik" (oder Vermächtnis), mit dem man sich befassen muss. Bevor Sprachen von Grund auf OO waren, gab es Bibliotheksfunktionen wie StrToInt () und IntToStr (). Sie führten Konvertierungen durch, es waren Operationen, daher machte es Sinn, sie SomethingToSomethingelse () zu nennen. Immerhin ist To aktiver als As. Ich denke hier besonders an Delphi.

Bei der Entwicklung von C # mit dem Ehrgeiz, stets OO zu verwenden, war es sinnvoll, eine Methode für das Objekt now integer zu verwenden, mit der die Ganzzahl in eine Zeichenfolge konvertiert wird. Obwohl wir auch eine Convert-Klasse haben, ist die Konvertierung in einen String so verbreitet, dass sie zu einer virtuellen Methode für ein Objekt gemacht wurde. Die Designer haben vielleicht gedacht, dass ToString den Leuten aus dem alten Paradigma vertrauter ist, und vielleicht haben wir deshalb eine virtuelle Methode ToString () und keine virtuelle Eigenschaft AsString.

Martin Maat
quelle
3
Was ist toString()?
Deduplizierer
Da hast du mich aber erwischt. Ich denke, AsString wäre angemessener gewesen. Ich habe einige zusätzliche Gedanken, ich werde meine Antwort aktualisieren.
Martin Maat
Ich glaube nicht, dass diese Antwort den Konventionen in C # wirklich entspricht. Z.B. ToList () und AsEnumerable () geben beide komplexe Objekte zurück. Der Unterschied besteht darin, dass ToList () immer ein neues Objekt zurückgibt, während AsEnumerable () eine Ansicht oder einen Adapter über das ursprüngliche Objekt zurückgibt.
JacquesB
@JaquesB Anscheinend wurden hier und da unterschiedliche Ideen angewendet. Delphi verfügt über die Eigenschaften AsInteger und AsString für TField-Objekte (die Datenbankfelder einschließen). Ich bin vielleicht voreingenommen. Andererseits ist die Frage mit Java markiert, nicht mit C # oder Delphi.
Martin Maat