Qual è la differenza tra i prefissi del nome del metodo "to" e "as"? [chiuso]


78

Qual è la differenza tra "to" e "as" come i prefissi dei nomi dei metodi

  • elencare(),
  • asList (),
  • eccetera...

Quando usare quale quando si progetta un metodo?

Risposte:


120

Si toXYZ()prevede che una funzione esegua una conversione e restituisca un nuovo oggetto indipendente (sebbene l'immutabilità consenta l'ottimizzazione, java.lang.String.toString()restituisce semplicemente l'oggetto).
Ad esempio, in C ++ abbiamo std::bitset::to_ulong()che può facilmente fallire, e un'intera pletora to_string(), facendo una conversione (più o meno) complessa e allocando memoria.

asXYZ()D'altra parte, una funzione dovrebbe restituire una vista (potenzialmente diversa) della sorgente, facendo un lavoro minimo.
Ad esempio, in C ++ abbiamo std::as_const()che restituisce solo un riferimento costante, e più coinvolto, std::forward_as_tupleche fa riferimento anche ai suoi argomenti per riferimento.


19
Si scopre che esiste un precedente esistente per questo. In generale, As [qualcosa] sarà simile a un cast, mentre To [qualcosa] costruisce un nuovo oggetto (di tipo diverso) da uno esistente. Nel caso di ToList, sarà O (n) e quasi sicuramente più costoso di un "As". Vedi stackoverflow.com/questions/17968469/…
Robert Harvey il

5
Fa parte della selezione di nomi descrittivi e anche se questa distinzione specifica non è codificata nello standard di codifica, la violazione infrange il Principio del minimo stupore .
Deduplicatore

11
Lo descriverei come, istintivamente, penserei a "to" come "cambia in" e "come" come "tratta come". Il primo implica il lavoro per cambiare la cosa, il secondo implica che è solo una differenza nel modo in cui ci lavori.
Latty,

6
Se significa qualcosa, dovrebbe significare questo. Suggerirei che spesso non significa nulla, quindi non farei affidamento su di esso in un codice casuale di terze parti (senza vedere qualcosa nei documenti). Sarebbe comunque una buona convenzione adottare in una base di codice.
Ben

4
Questa risposta è accurata anche in C ++: ad esempio std::to_string(x)crea un nuovo oggetto stringa, ma std::as_const(x)crea un riferimento (una vista) dell'oggetto esistente.
Quuxplusone,

13

Onestamente, potrebbe essere solo nominare l'incoerenza. Se ad alcuni oggetti di libreria standard di Smalltalk, per esempio, tutti i metodi che fanno "conversioni complesse" o "ritorno rappresentazioni semplici in un altro tipo" sono preceduti dal prefisso as, come in asString, asFloat, asSeconds, e il metodo standard per la conversione di qualsiasi cosa a qualsiasi altra cosa, as: aClass.

In Ruby, gli stessi tipi di metodi sono precedute to_, come to_s, to_a, to_h, abbreviazione di string, arraye hashrispettivamente.

Nessuna delle librerie standard sembra distinguere tra diversi tipi di conversioni, probabilmente perché dovrebbe essere considerata come un dettaglio di implementazione.

Tuttavia, in Java vediamo un sacco di confusione. Come lei ha ricordato, c'è toString, asListe così via. Credo che queste siano solo un'incoerenza nella denominazione, perché se provi a definire un significato diverso per ciascun prefisso, troverai sempre un contro-esempio da qualche altra parte nella libreria standard.

Quindi, in ogni caso, direi che è importante che tu e il tuo team scegliate un prefisso e lo utilizziate in modo coerente in tutto il codice. La coerenza è la chiave, quindi le persone non sono lasciate a meravigliarsi, come dovevi.


1
Non ci credo: scegliere uno stile per un'intera squadra, piuttosto scegliere uno stile per casi simili in un modulo, in modo coerente.
Daniel Hári,

12
In Java, toStringcrea una nuova stringa completamente disconnessa dall'oggetto (e non c'è altro modo a causa dell'immutabilità). Lo stesso vale, ad esempio, per Collection#toArray, mentre Arrays#asListrestituisce una vista dell'array, che è collegata in modo bidirezionale (la modifica dell'array modifica l'elenco e viceversa). Quindi è abbastanza coerente, anche se potrebbero esserci delle eccezioni. Scegliere un prefisso sarebbe sbagliato. Se ci fosse Arrays#toList, mi aspetto che crei un nuovo elenco con un nuovo array sottostante.
maaartinus,

Penso che Smalltalk abbia appena fatto un errore lì, non hanno capito la convenzione. È una convenzione difficile da capire (e persino notare) perché è così astratta e non ha un impatto particolare. Anche l'atto stesso di porre questa domanda richiede alcune intuizioni.
usr

3
@usr Smalltalk potrebbe essere stato progettato prima che diventasse una convenzione
Bergi,

6

Anche se c'è già una risposta accettata, sembra concentrarsi sul C ++, mentre la domanda è taggata con Java . In Java, il primo esempio che viene in mente per questo tipo di cose è Arrays.asList , che restituisce, essenzialmente, una vista di un array, racchiuso in un elenco. L'array sottostante e l'elenco sono comunque connessi; le modifiche all'array si riflettono nell'elenco e viceversa. Tuttavia, l'array restituito dal metodo toArray dell'elenco è indipendente dall'array originale e dall'elenco:

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

Detto questo, non c'è garanzia che ogni sviluppatore di biblioteche segua questa convenzione, quindi è comunque necessario controllare la documentazione per scoprire se questo è il comportamento che si otterrà da un codice sconosciuto.

L'altro posto che ho visto come metodi ... () usati frequentemente è nei tipi di downcasting ai sottotipi. Ad esempio, se si dispone di un insieme enumerato di sottotipi, si potrebbe finire con un codice come:

  /**
   * 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();
      }
    }
  }

1

La differenza che ho notato (solo ora pensandoci) è

  • In genere si converte in un diverso tipo di riferimento (un oggetto piuttosto complesso)
  • Come in genere restituisce un tipo di valore semplice

Quindi vediamo AsInteger e AsString e vediamo ToArray e ToStringList.

Implica una conversione, che ha senso (è un movimento, un processo). Come implica una rappresentazione, un modo di esprimere l'oggetto originale.

Un altro modo di guardare a questo:

  • A è un'operazione, quindi la useresti per i metodi.
  • Come è una rappresentazione semplice, quindi la useresti per le proprietà.

E poi c'è "arte nota" (o eredità) da affrontare. Prima che le lingue fossero completamente OO da zero, avresti funzioni di libreria come StrToInt () e IntToStr (). Eseguivano conversioni, erano operazioni, quindi aveva senso chiamarle SomethingToSomethingelse (). Dopotutto, To è più attivo di As. Sto pensando in particolare a Delphi qui.

Quando C # è stato progettato con l'ambizione di andare OO fino in fondo, aveva senso avere un metodo sull'oggetto ora intero che convertisse l'intero in una stringa. Anche se abbiamo anche una classe Convert, la conversione in stringa è così comune che è stato creato un metodo virtuale sull'oggetto. I progettisti potrebbero aver capito che ToString sarebbe più familiare alle persone del vecchio paradigma e forse questo è il motivo per cui abbiamo ottenuto un metodo virtuale ToString () e non una proprietà virtuale AsString.


3
Che dire toString()?
Deduplicatore

Mi hai portato lì. Penso che AsString sarebbe stato più appropriato. Ho alcuni pensieri aggiuntivi, aggiornerò la mia risposta.
Martin Maat,

Non credo che questa risposta maturi davvero le convenzioni in C #. Per esempio. ToList () e AsEnumerable () restituiscono entrambi oggetti complessi, la differenza è ToList () restituisce sempre un nuovo oggetto mentre AsEnumerable () restituisce una vista o un adattatore sull'oggetto originale.
JacquesB,

@JaquesB Idee apparentemente diverse sono state applicate qua e là. Delphi ha proprietà AsInteger e AsString sugli oggetti TField (che incapsulano i campi del database). Potrei essere stato di parte da questo. Ma poi di nuovo, la domanda è taggata con Java, non con C # o Delphi.
Martin Maat,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.