Quelle est la différence entre les préfixes de nom de méthode "to" et "as"? [fermé]

78

Quelle est la différence entre les préfixes de nom de méthode "to" et "as" comme

  • lister(),
  • asList (),
  • etc...

Quand utiliser lequel pour concevoir une méthode?

Daniel Hári
la source

Réponses:

120

Une toXYZ()fonction doit effectuer une conversion et renvoyer un nouvel objet indépendant (bien que l’immuabilité permette une optimisation, elle java.lang.String.toString()ne renvoie que l’objet).
Par exemple, en C ++, nous avons std::bitset::to_ulong()ce qui peut facilement échouer, et toute une pléthore de to_string()conversions (plus ou moins) complexes et d’allocation de mémoire.

En asXYZ()revanche, une fonction est supposée renvoyer une vue (potentiellement différente) de la source, en effectuant un travail minimal.
Par exemple, en C ++, nous avons std::as_const()simplement une référence constante, et la plus impliquée, std::forward_as_tuplequi fait également référence à ses arguments par référence.

Déduplicateur
la source
19
Il s'avère qu'il existe un précédent pour cela. En général, As [quelque chose] ressemblera à un casting, alors que To [quelque chose] construit un nouvel objet (d'un type différent) à partir d'un objet existant. Dans le cas de ToList, ce sera O (n) et presque certainement plus cher qu'un "As". Voir stackoverflow.com/questions/17968469/…
Robert Harvey
5
Cela fait partie de la sélection de noms descriptifs, et même si cette distinction spécifique n'est pas codifiée dans la norme de codage, le fait de la violer viole le principe de moindre étonnement .
Déduplicateur
11
Je le décrirais comme, instinctivement, je penserais à "changer" en "et" comme "traiter comme". La première implique un travail pour changer la chose, la dernière implique que c'est simplement une différence dans la façon dont vous travaillez avec elle.
Latty
6
Si cela signifie quelque chose, cela devrait signifier cela. Je dirais que cela ne veut souvent pas dire quelque chose, alors je ne m'en remettrais pas dans un code tiers aléatoire (sans voir quelque chose dans la documentation). Ce serait une bonne convention à adopter dans une base de code cependant.
Ben
4
Cette réponse est également précise en C ++: par exemple, std::to_string(x)crée un nouvel objet chaîne, mais std::as_const(x)crée une référence (une vue) de l'objet existant.
Quuxplusone
13

Honnêtement, il s’agit peut-être simplement de nommer une incohérence. Si certains objets de la bibliothèque standard dans Smalltalk, par exemple, toutes les méthodes qui font « conversions complexes » ou « retour de simples représentations dans un autre type » sont préfixés avec as, comme asString, asFloat, asSecondset la méthode standard pour convertir quoi que ce soit à quoi que ce soit d' autre, as: aClass.

Dans Ruby, les mêmes types de méthodes sont préfixées avec to_, comme to_s, to_a, to_h, court pour string, arrayet hashrespectivement.

Aucune des bibliothèques standard ne semble différencier les différents types de conversions, probablement parce que cela devrait être considéré comme un détail d'implémentation.

Cependant, en Java, nous voyons beaucoup de confusion. Comme vous l' avez mentionné, il y a toString, asListet ainsi de suite. Je pense que ce ne sont que des incohérences dans les noms, car si vous essayez de définir un sens différent pour chaque préfixe, vous trouverez toujours un contre-exemple ailleurs dans la bibliothèque standard.

Donc, dans tous les cas, je dirais que l’important est que vous et votre équipe choisissiez un préfixe et l’utilisiez de manière cohérente dans le code. La cohérence est la clé, de sorte que les gens ne sont pas laissés à se demander, comme vous le deviez.

MichelHenrich
la source
1
Je n'y crois pas: choisir un style pour toute une équipe, plutôt choisir un style pour des cas similaires dans un module, de manière cohérente.
Daniel Hári
12
En Java, toStringcrée une nouvelle chaîne complètement déconnectée de l'objet (et il n'y a pas d'autre moyen à cause de l'immuabilité). Il en va de même, par exemple, pour Collection#toArray, tandis que Arrays#asListrenvoie une vue du tableau qui est connecté de manière bidirectionnelle (la mutation du tableau modifie la liste et inversement). C'est donc assez cohérent, même s'il peut y avoir des exceptions. Choisir un préfixe serait une erreur. Si Arrays#toListtel était le cas , je m'attendrais à ce qu'il crée une nouvelle liste avec un nouveau tableau sous-jacent.
Maaartinus
Je pense que Smalltalk vient de faire une erreur, ils n'ont pas compris la convention. C'est une convention difficile à comprendre (et même à remarquer) car elle est très abstraite et n'a pas d'impact majeur. Même l'acte même de poser cette question nécessite un aperçu.
Usr
3
@usr Smalltalk aurait pu être conçu avant de devenir une convention
Bergi
6

Bien qu'il existe déjà une réponse acceptée, il semble se concentrer sur C ++, alors que la question est étiquetée avec Java . En Java, le premier exemple qui nous vient à l’esprit pour ce genre de chose est Arrays.asList , qui renvoie essentiellement une vue d’un tableau, encapsulée dans une liste. Le tableau sous-jacent et la liste sont toujours connectés. les modifications apportées au tableau sont reflétées dans la liste, et inversement. Cependant, le tableau renvoyé par la méthode toArray de la liste est indépendant du tableau d'origine et de la 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"
}

Cela dit, rien ne garantit que chaque développeur de bibliothèque respecte cette convention. Vous devez donc consulter la documentation pour savoir s'il s'agit du comportement que vous obtiendrez avec un code inconnu.

L'autre endroit que j'ai vu comme méthodes ... () est fréquemment utilisé pour la conversion de types en sous-types. Par exemple, si vous avez un ensemble énuméré de sous-types, vous pourriez alors vous retrouver avec un code comme:

  /**
   * 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
la source
1

La différence que j’ai remarquée (juste maintenant en y réfléchissant) est que

  • Pour convertir typiquement vers un type de référence différent (un objet quelque peu complexe)
  • Comme renvoie généralement un type de valeur simple

Nous voyons donc AsInteger et AsString et nous voyons ToArray et ToStringList.

Impliquer une conversion qui a du sens (c'est un mouvement, un processus). Comme implique une représentation, une manière d’exprimer l’objet d’origine.

Une autre façon de regarder cela:

  • To est une opération, vous l'utiliserez donc pour les méthodes.
  • Comme c'est une représentation simple, vous l'utiliseriez pour les propriétés.

Et puis il y a "l'art antérieur" (ou l'héritage) à traiter. Avant que les langues soient totalement OO, vous disposiez de fonctions de bibliothèque telles que StrToInt () et IntToStr (). Ils effectuaient des conversions, c'étaient des opérations, il était donc logique de les appeler SomethingToSomethingelse (). Après tout, To est plus actif que As. Je pense particulièrement à Delphi ici.

Lorsque C # a été conçu avec l'ambition de devenir totalement opérationnel (OO), il était logique de disposer d'une méthode sur l'objet désormais entier qui convertirait l'entier en chaîne. Bien que nous ayons également une classe Convert, la conversion en chaîne est si courante qu'elle a été transformée en méthode virtuelle sur objet. Les concepteurs ont peut-être pensé que ToString serait plus familier aux personnes de l'ancien paradigme. C'est peut-être pour cette raison que nous avons obtenu une méthode virtuelle, ToString (), et non une propriété virtuelle, AsString.

Martin Maat
la source
3
Qu'en est- il toString()?
Déduplicateur
Vous m'avez bien eu. Je pense qu'AsString aurait été plus approprié. Si vous avez quelques réflexions supplémentaires, je mettrai à jour ma réponse.
Martin Maat
Je ne pense pas que cette réponse modifie vraiment les conventions en C #. Par exemple. ToList () et AsEnumerable () renvoient tous les deux des objets complexes. La différence est que ToList () renvoie toujours un nouvel objet, tandis que AsEnumerable () renvoie une vue ou un adaptateur sur l'objet d'origine.
JacquesB
@JaquesB Apparemment, différentes idées ont été appliquées ici et là. Delphi a les propriétés AsInteger et AsString sur les objets TField (qui encapsulent les champs de la base de données). J'ai peut-être été biaisé par cela. Mais là encore, la question est balisée avec Java, pas avec C # ni Delphi.
Martin Maat