¿Cuál es la diferencia entre los prefijos de nombre de método "to" y "as"? [cerrado]

78

¿Cuál es la diferencia entre "a" y "como" prefijos de nombre de método como

  • Listar(),
  • asList (),
  • etc ...

¿Cuándo usar cuál al diseñar un método?

Daniel Hári
fuente

Respuestas:

120

Se toXYZ()espera que una función realice una conversión y devuelva un nuevo objeto independiente (aunque la inmutabilidad permite la optimización, java.lang.String.toString()solo devuelve el objeto).
Como ejemplo, en C ++ tenemos std::bitset::to_ulong()que puede fallar fácilmente, y una gran cantidad de to_string()todos haciendo una conversión (más o menos) compleja y asignando memoria.

Por asXYZ()otro lado, se espera que una función devuelva una vista (potencialmente diferente) de la fuente, haciendo un trabajo mínimo.
Como ejemplo, en C ++ tenemos el std::as_const()que solo devuelve una referencia constante, y el más involucrado std::forward_as_tupleque también se refiere a sus argumentos por referencia.

Deduplicador
fuente
19
Resulta que hay un precedente existente para esto. En general, As [algo] será similar a un elenco, mientras que A [algo] construye un nuevo objeto (de un tipo diferente) a partir de uno existente. En el caso de ToList, será O (n) y casi seguro que será más caro que un "As". Ver stackoverflow.com/questions/17968469/…
Robert Harvey
55
Es parte de la selección de nombres descriptivos, e incluso si esta distinción específica no está codificada en el estándar de codificación, violarla rompe el Principio de menor asombro .
Deduplicador
11
Lo describiría como, instintivamente, pensaría en "a" como "cambio a" y "como" como "tratar como". Lo primero implica trabajar para cambiar la cosa, lo segundo implica que es solo una diferencia en cómo trabajas con eso.
Latty
66
Si significa algo, debería significar esto. Sin embargo, sugeriría que a menudo no significa nada, por lo que no confiaría en él en código aleatorio de terceros (sin ver algo en los documentos). Sin embargo, sería una buena convención adoptar en una base de código.
Ben
44
Esta respuesta también es precisa en C ++: por ejemplo, std::to_string(x)crea un nuevo objeto de cadena, pero std::as_const(x)crea una referencia (una vista) del objeto existente.
Quuxplusone
13

Honestamente, puede ser solo nombrar inconsistencia. Si vistazo a los objetos de la biblioteca estándar en Smalltalk, por ejemplo, todos los métodos que hacen "conversiones complejas" o "retorno representaciones simples en otro tipo" se puede anteponer as, como en asString, asFloat, asSeconds, y el método estándar para convertir cualquier cosa a cualquier otra cosa, as: aClass.

En Ruby, los mismos tipos de métodos tienen el prefijo to_, como en to_s, to_a, to_h, abreviatura de string, arrayy hashrespectivamente.

Ninguna de las bibliotecas estándar parece diferenciar entre diferentes tipos de conversiones, probablemente porque debería considerarse como un detalle de implementación.

Sin embargo, en Java vemos mucha confusión. Como usted ha mencionado, hay toString, asListy así sucesivamente. Creo que estos son solo una inconsistencia de nombres, porque si intenta definir un significado diferente para cada prefijo, siempre encontrará un contraejemplo en otro lugar de la biblioteca estándar.

En cualquier caso, diría que lo importante es que usted y su equipo elijan un prefijo y lo usen de manera consistente en todo el código. La consistencia es la clave, por lo que las personas no deben preguntarse, como tenía que hacerlo.

MichelHenrich
fuente
1
No creo en: elegir un estilo para todo un equipo, más bien elegir un estilo para casos similares en un módulo, de manera consistente.
Daniel Hári
12
En Java, toStringcrea una nueva cadena completamente desconectada del objeto (y no hay otra forma debido a la inmutabilidad). Lo mismo ocurre, por ejemplo, for Collection#toArray, while Arrays#asListdevuelve una vista de la matriz, que está conectada bidireccionalmente (la mutación de la matriz cambia la lista y viceversa). Entonces, es bastante consistente, aunque puede haber excepciones. Elegir un prefijo estaría mal. Si lo hubiera Arrays#toList, entonces esperaría que creara una nueva lista con una nueva matriz subyacente.
maaartinus
Creo que Smalltalk simplemente cometió un error allí, no entendieron la convención. Es una convención difícil de entender (e incluso notar) porque es muy abstracta y no es particularmente impactante. Incluso el mismo acto de hacer esta pregunta requiere una idea.
usr
3
@usr Smalltalk podría haber sido diseñado antes de convertirse en una convención
Bergi
6

Si bien ya hay una respuesta aceptada, parece centrarse en C ++, mientras que la pregunta está etiquetada con Java . En Java, el primer ejemplo que viene a la mente para este tipo de cosas es Arrays.asList , que devuelve, esencialmente, una vista de una matriz, envuelta en una lista. Sin embargo, la matriz subyacente y la lista todavía están conectadas; los cambios en la matriz se reflejan en la lista y viceversa. Sin embargo, la matriz devuelta por el método toArray de la lista es independiente de la matriz original y de la lista:

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"
}

Dicho todo esto, no hay garantía de que todos los desarrolladores de bibliotecas sigan esta convención, por lo que aún debe verificar la documentación para averiguar si este es el comportamiento que obtendrá de un código desconocido.

El otro lugar que he visto como ... () métodos utilizados con frecuencia es en la conversión de tipos a subtipos. Por ejemplo, si tiene un conjunto de subtipos enumerados, entonces podría terminar con un código como:

  /**
   * 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
fuente
1

La diferencia que noté (justo ahora al pensarlo) es

  • Por lo general, se convierte a un tipo de referencia diferente (un objeto algo complejo)
  • Como normalmente devuelve un tipo de valor simple

Entonces vemos AsInteger y AsString y vemos ToArray y ToStringList.

Implica una conversión, que tiene sentido (es un movimiento, un proceso). Como implica una representación, una forma de expresar el objeto original.

Otra forma de mirar esto:

  • To es una operación, por lo que lo usaría para métodos.
  • Como es una representación simple, la usaría para propiedades.

Y luego hay que tratar con el "arte previo" (o legado). Antes de que los idiomas fueran completamente OO desde cero, tenía funciones de biblioteca como StrToInt () e IntToStr (). Realizaron conversiones, eran operaciones, por lo que tenía sentido llamarlos SomethingToSomethingelse (). Después de todo, To es más activo que As. Estoy particularmente pensando en Delphi aquí.

Cuando C # se diseñó con la ambición de ir OO hasta el final, tenía sentido tener un método en el objeto ahora entero que convertiría el entero en una cadena. Aunque también tenemos una clase Convert, la conversión a cadena es tan común que se hizo un método virtual en el objeto. Los diseñadores pueden haber pensado que ToString sería más familiar para las personas del viejo paradigma y quizás es por eso que obtuvimos un método virtual ToString () y no una propiedad virtual AsString.

Martin Maat
fuente
3
¿Qué hay de toString()?
Deduplicador
Me atrapaste. Creo que AsString habría sido más apropiado. Si tengo algunas ideas adicionales, actualizaré mi respuesta.
Martin Maat
No creo que esta respuesta realmente coincida con las convenciones en C #. P.ej. ToList () y AsEnumerable () devuelven objetos complejos, la diferencia es que ToList () siempre devuelve un nuevo objeto mientras AsEnumerable () devuelve una vista o adaptador sobre el objeto original.
JacquesB
@JaquesB Aparentemente se han aplicado ideas diferentes aquí y allá. Delphi tiene propiedades AsInteger y AsString en objetos TField (que encapsulan los campos de la base de datos). Puede haber sido parcial por esto. Pero, de nuevo, la pregunta está etiquetada con Java, no con C # o Delphi.
Martin Maat