Qual è il nome migliore per un metodo "add" non mutante in una collezione immutabile?


229

Ci scusiamo per il titolo waffly - se potessi trovare un titolo conciso, non avrei dovuto porre la domanda.

Supponiamo che io abbia un tipo di elenco immutabile. Ha un'operazione Foo(x)che restituisce un nuovo elenco immutabile con l'argomento specificato come elemento aggiuntivo alla fine. Quindi, per creare un elenco di stringhe con valori "Hello", "immutable", "world" puoi scrivere:

var empty = new ImmutableList<string>();
var list1 = empty.Foo("Hello");
var list2 = list1.Foo("immutable");
var list3 = list2.Foo("word");

(Questo è il codice C #, e sono molto interessato a un suggerimento C # se ritieni che la lingua sia importante. Non è fondamentalmente una domanda di lingua, ma gli idiomi della lingua possono essere importanti.)

L'importante è che gli elenchi esistenti non vengano modificati da Foo, quindi empty.Countrestituirebbe comunque 0.

Un altro modo (più idiomatico) per arrivare al risultato finale sarebbe:

var list = new ImmutableList<string>().Foo("Hello")
                                      .Foo("immutable")
                                      .Foo("word");

La mia domanda è: qual è il nome migliore per Foo?

EDIT 3 : Come rivelerò più avanti, il nome del tipo potrebbe non essere effettivamente ImmutableList<T>, il che rende chiara la posizione. Immagina invece che sia TestSuitee che sia immutabile perché l'intero quadro di cui fa parte è immutabile ...

(Fine della modifica 3)

Opzioni che ho escogitato finora:

  • Add: comune in .NET, ma implica la mutazione dell'elenco originale
  • Cons: Credo che questo sia il nome normale nei linguaggi funzionali, ma privo di significato per coloro che non hanno esperienza in tali linguaggi
  • Plus: il mio preferito finora, non implica mutazione per me . Apparentemente questo è usato anche in Haskell ma con aspettative leggermente diverse (un programmatore Haskell potrebbe aspettarsi di aggiungere due liste insieme invece di aggiungere un singolo valore all'altra lista).
  • With: coerente con alcune altre convenzioni immutabili, ma non ha abbastanza la stessa "aggiunta" ad esso IMO.
  • And: non molto descrittivo.
  • Sovraccarico dell'operatore per +: non mi piace molto; In genere penso che gli operatori dovrebbero essere applicati solo a tipi di livello inferiore. Sono disposto a essere persuaso però!

I criteri che sto usando per scegliere sono:

  • Fornisce l'impressione corretta del risultato della chiamata al metodo (ovvero che è l'elenco originale con un elemento aggiuntivo)
  • Rende il più chiaro possibile che non muta l'elenco esistente
  • Sembra ragionevole quando incatenati insieme come nel secondo esempio sopra

Si prega di chiedere maggiori dettagli se non mi sto chiarendo abbastanza ...

EDIT 1: Ecco il mio ragionamento per preferire Plusa Add. Considera queste due righe di codice:

list.Add(foo);
list.Plus(foo);

Dal mio punto di vista (e questa è una cosa personale) quest'ultima è chiaramente buggy - è come scrivere "x + 5;" come una dichiarazione a sé stante. La prima riga sembra a posto, finché non ti ricordi che è immutabile. In effetti, il modo in cui l'operatore plus da solo non muta i suoi operandi è un altro motivo per cui Plusè il mio preferito. Senza il leggero fastidio del sovraccarico dell'operatore, fornisce comunque le stesse connotazioni, che includono (per me) la non mutazione degli operandi (o metodo target in questo caso).

EDIT 2: motivi per non gradire Aggiungi.

Diverse risposte sono effettivamente: "Vai con Aggiungi. Ecco cosa DateTimefa, e Stringha Replacemetodi ecc. Che non rendono evidente l'immutabilità." Sono d'accordo - qui c'è la precedenza. Tuttavia, ho visto un sacco di persone chiamano DateTime.Addo String.Replacee si aspettano la mutazione . Ci sono un sacco di domande sui newsgroup (e probabilmente SO se scavo in giro) a cui si risponde "Stai ignorando il valore di ritorno di String.Replace; le stringhe sono immutabili, viene restituita una nuova stringa".

Ora, dovrei rivelare una sottigliezza alla domanda: il tipo potrebbe non essere in realtà un elenco immutabile, ma un tipo immutabile diverso. In particolare, sto lavorando a un framework di benchmarking in cui aggiungi test a una suite e che crea una nuova suite. Potrebbe essere ovvio che:

var list = new ImmutableList<string>();
list.Add("foo");

non realizzerà nulla, ma diventa molto più oscuro quando lo cambi in:

var suite = new TestSuite<string, int>();
suite.Add(x => x.Length);

Sembra che dovrebbe essere a posto. Considerando che questo, per me, rende più chiaro l'errore:

var suite = new TestSuite<string, int>();
suite.Plus(x => x.Length);

Sta solo chiedendo di essere:

var suite = new TestSuite<string, int>().Plus(x => x.Length);

Idealmente, vorrei che ai miei utenti non venisse detto che la suite di test è immutabile. Voglio che cadano nella fossa del successo. Questo potrebbe non essere possibile, ma mi piacerebbe provare.

Mi scuso per l'eccessiva semplificazione della domanda originale parlando solo di un tipo di elenco immutabile. Non tutte le raccolte sono auto-descrittive come ImmutableList<T>:)


2
@Adam: No, quest'ultimo è chiaramente difettoso. Entrambi sono in realtà buggy (dato che non stanno facendo nulla con il risultato) - ma il primo non mi sembra buggy.
Jon Skeet,

36
Un uncat è un cane?
Michael Myers

7
Concat / Condog ... funziona per me! ;)
gnovice,

11
Uncat - sarebbe un gatto zombi.
Erik Forbes,

2
@Trap: Questo fa schifo in termini di rendere fluida l'API.
Jon Skeet,

Risposte:


130

In situazioni del genere, di solito vado con Concat. Ciò di solito implica per me che viene creato un nuovo oggetto.

var p = listA.Concat(listB);
var k = listA.Concat(item);

3
Questo è quello che uso, perché è quello che utilizza System.Linq.Enumerable: la decisione è già stata presa. :) Non posso essere l'unica persona che ha definito il proprio sovraccarico dell'estensione Concat su IEnumerable ad accettare un singolo valore da aggiungere.
Daniel Earwicker,

9
+1 Questa è la risposta corretta per mantenere la coerenza dei nomi all'interno del framework.
Sam Harwell,

A meno che non mi manchi, System.Linq.Enumerable (e Linq in generale) usa solo Concat () per "sequenza + sequenza", mai "oggetto + sequenza". Il problema che qualcuno "potrebbe aspettarsi di aggiungere due elenchi insieme anziché aggiungere un singolo valore all'altra lista" è stato esplicitamente indicato come motivo per non utilizzare una delle altre opzioni originali.
Ssswift,

119

Andrei con contro, per una semplice ragione: significa esattamente quello che vuoi che faccia.

  1. Sono un grande fan di dire esattamente cosa intendo, soprattutto nel codice sorgente. Un principiante dovrà cercare la definizione di Contro solo una volta, ma poi leggerla e usarla mille volte. Trovo che, a lungo termine, sia meglio lavorare con sistemi che semplificano il caso comune, anche se il costo iniziale è leggermente più alto.

  2. Il fatto che sarebbe "insignificante" per le persone senza esperienza FP è in realtà un grande vantaggio. Come hai sottolineato, tutte le altre parole che hai trovato hanno già un significato e quel significato è leggermente diverso o ambiguo. Un nuovo concetto dovrebbe avere una nuova parola (o in questo caso, una vecchia). Preferirei che qualcuno dovesse cercare la definizione di Contro, piuttosto che presumere erroneamente sappia cosa fa Add.

  3. Altre operazioni prese in prestito da linguaggi funzionali spesso mantengono i loro nomi originali, senza apparenti catastrofi. Non ho visto alcuna spinta a trovare sinonimi di "mappa" e "ridurre" che suonano più familiari ai non FPer, né vedo alcun vantaggio nel farlo.

(Informativa completa: sono un programmatore Lisp, quindi so già cosa significa Contro.)


16
Non dimenticare che la rilevabilità è importante, se digito "testSuite". e guarda l'elenco dei metodi, vorrei vedere un metodo che suggerisce la cosa giusta. Probabilmente non cercherò un nome senza senso (per me) sulla sfortuna che è quello che voglio.
Jon Skeet,

33
Se mi sentissi snarky, farei un metodo Add che semplicemente generava un'eccezione con message = "Usa i contro per anteporre a un ImmutableList". :-)
Ken,

2
Non ucciderà nessuno leggere alcune righe di commenti che spiegano perché il nome è quello che è, e riferirli, per esempio, alla "Struttura e interpretazione dei programmi per computer" di Abelson & Sussman.
John R. Strohm,

16
Tradizionalmente, i contro si aggiungono all'inizio piuttosto che alla fine. Quindi è un nome potenzialmente fuorviante per il metodo descritto.
walkytalky,

16
Solo per salvare il prossimo programmatore non funzionale un clic o 3 ... en.wikipedia.org/wiki/Cons dalla parola "costruire", l'espressione "contro x su y" significa costruire un nuovo oggetto con ( contro xy)
Myster,

59

In realtà mi piace And, soprattutto in modo idiomatico. Mi piacerebbe particolarmente se tu avessi una proprietà di sola lettura statica per la lista vuota e forse rendi privato il costruttore, quindi devi sempre costruire dalla lista vuota.

var list = ImmutableList<string>.Empty.And("Hello")
                                      .And("Immutable")
                                      .And("Word");

Mi piace l'idea vuota. Non sono ancora convinto di E però. È solo un po 'blah.
Jon Skeet,

Sembra più come pensare a costruire un elenco di cose in linguaggio naturale. Se lo leggi ad alta voce sembra più intuitivo di Aggiungi o Più. "list" è l'elenco vuoto e "Hello" e "Immutable" e "Word". Concordo sul fatto che è meno chiaro in isolamento, però.
tvanfosson,

52

Ogni volta che sono in difficoltà con la nomenclatura, raggiungo le interwebs.

thesaurus.com restituisce questo per "aggiungi":

Definizione: adiacente, aumentare; fare ulteriori commenti

Sinonimi: apporre, annettere, ante, aggiungere, aumentare, rinforzare, potenziare, aumentare, caricare, continuare, inserire, inserire, rimpolpare, riscaldare, aumentare, aumentare, agganciare, agganciare, agganciare con, include, jack up, jazz up, unisci insieme, pad, parlay, piggyback, plug in, pour it on, rispondi, corri, dì altro, schiaffi, snowball, soup up, speed up, spike, step up, supplemento, addolcimento, tack on, tag

Mi piace il suono di Adjoin, o più semplicemente Join. Questo è quello che stai facendo, vero? Il metodo potrebbe anche applicarsi all'unione di altri ImmutableList<>.


1
In un certo senso mi piace anche 'Unisci' ma, nella maggior parte dei casi, quando unisci 2 oggetti, finisci con 1. In questo caso, se unisci 2 oggetti, stai effettivamente creando un nuovo oggetto.
Programmatore fuorilegge il

1
Non conosco alcun caso in .NET, Perl, PHP o persino VBScript in cui Join implica una mutazione. Il design è tale che A e B si uniscono per creare C, dove C è sempre una nuova entità.
spoulson,

Mi piace Join e concordo pienamente con thesaurus.com :) Usalo sempre in caso di dubbi su un nome.
Skurmedel,

var suite = new TestSuite <string, int> () .Join (x => x.Length);
Sly Gryphon,

3
Vai con Piggyback, imo. O HookUpWith.
Chris Marasti-Georg,

48

Personalmente, mi piace. Con (). Se stavo usando l'oggetto, dopo aver letto la documentazione o i commenti sul codice, sarebbe chiaro cosa fa, e legge ok nel codice sorgente.

object.With("My new item as well");

Oppure aggiungi "Insieme" con esso .. :)

object.AlongWith("this new item");

+1. "WITH" è un operatore infix in SETL che fa la stessa cosa. Se SETL lo usa, allora deve essere giusto :-)
finnw,

1
Bah ... Chi usa più VB? :) Uh .. Opps .. Era ad alta voce? heh .. Ma, no, in tutta serietà, è per questo che ho considerato "AlongWith", che avrebbe rimosso il problema VB. Ci sono solo circa un milione di modi diversi in cui potrebbe andare con questo ... Voglio dire, anche quelli folli come: object.Plus () o Object.ExistingPlus () ... ecc ... È una dannata buona domanda che pubblicato, tuttavia ... heh ..
LarryF

33

Ho finito per andare con Aggiungi per tutte le mie collezioni immutabili in BclExtras . Il motivo è che è un nome facile e prevedibile. Non sono così preoccupato per le persone che confondono Aggiungi con un'aggiunta mutante poiché il nome del tipo ha il prefisso Immutable.

Per un po 'ho considerato i contro e altri nomi di stile funzionale. Alla fine li ho scontati perché non sono così famosi. Sicuramente i programmatori funzionali capiranno ma non sono la maggior parte degli utenti.

Altri nomi: hai menzionato:

  • Inoltre: sono desideroso / lavaggio su questo. Per me questo non lo distingue come un'operazione non mutante più di Add
  • Con: causerà problemi con VB (gioco di parole previsto)
  • Sovraccarico dell'operatore: la rilevabilità sarebbe un problema

Opzioni che ho considerato:

  • Concat: le stringhe sono immutabili e usano questo. Purtroppo è davvero buono solo per aggiungere alla fine
  • CopyAdd: Copia cosa? La fonte, l'elenco?
  • AddToNewList: forse un buon elenco. Ma che dire di una raccolta, stack, coda, ecc ...

Sfortunatamente non sembra esserci davvero una parola

  1. Sicuramente un'operazione immutabile
  2. Comprensibile per la maggior parte degli utenti
  3. Rappresentabile in meno di 4 parole

Diventa ancora più strano se consideri raccolte diverse da Elenco. Prendi ad esempio Stack. Anche i programmatori del primo anno possono dirti che gli stack hanno una coppia di metodi Push / Pop. Se crei un ImmutableStack e gli dai un nome completamente diverso, chiamiamolo Foo / Fop, hai appena aggiunto più lavoro per loro per usare la tua collezione.

Modifica: risposta a Plus Edit

Vedo dove stai andando con Plus. Penso che un caso più forte sarebbe effettivamente meno per la rimozione. Se vedessi quanto segue mi chiederei sicuramente a cosa stia pensando il programmatore

list.Minus(obj);

Il problema più grande che ho con Plus / Minus o una nuova associazione è che sembra eccessivo. La collezione stessa ha già un nome distintivo, il prefisso Immutable. Perché andare oltre aggiungendo il vocabolario il cui intento è quello di aggiungere la stessa distinzione del prefisso immutabile già fatto.

Vedo l'argomento del sito di chiamata. Lo rende più chiaro dal punto di vista di una singola espressione. Ma nel contesto dell'intera funzione sembra non necessario.

Modifica 2

Concordo sul fatto che le persone siano state sicuramente confuse da String.Concat e DateTime.Add. Ho visto diversi programmatori molto brillanti colpire questo problema.

Tuttavia, penso che ImmutableList sia un argomento diverso. Non c'è nulla in String o DateTime che lo stabilisce come Immutabile per un programmatore. Devi semplicemente sapere che è immutabile tramite qualche altra fonte. Quindi la confusione non è inaspettata.

ImmutableList non ha questo problema perché il nome definisce il suo comportamento. Potresti sostenere che le persone non sanno cosa sia Immutabile e penso che sia anche valido. Di certo non lo sapevo fino al 2 ° anno al college. Ma hai lo stesso problema con qualsiasi nome tu scelga invece di Aggiungi.

Modifica 3: Che dire di tipi come TestSuite che sono immutabili ma non contengono la parola?

Penso che questo porti a casa l'idea che non dovresti inventare nuovi nomi di metodi. Vale a dire perché esiste chiaramente un impulso per rendere immutabili i tipi al fine di facilitare operazioni parallele. Se ti concentri sulla modifica del nome dei metodi per le raccolte, il passaggio successivo saranno i nomi dei metodi mutanti su ogni tipo che usi immutabile.

Penso che sarebbe uno sforzo più prezioso concentrarsi invece sul rendere identificabili i tipi come Immutabili. In questo modo è possibile risolvere il problema senza ripensare ogni modello di metodo di mutazione là fuori.

Ora come puoi identificare TestSuite come immutabile? Nell'ambiente odierno penso che ci siano alcuni modi

  1. Prefisso con Immutable: ImmutableTestSuite
  2. Aggiungi un attributo che descriva il livello di immutabilità. Questo è sicuramente meno rilevabile
  3. Non molto altro.

La mia ipotesi / speranza è che gli strumenti di sviluppo inizieranno ad aiutare questo problema facilitando l'identificazione dei tipi immutabili semplicemente a vista (colore diverso, carattere più forte, ecc ...). Ma penso che questa sia la risposta oltre a cambiare tutti i nomi dei metodi.


Ho aggiunto motivi per la mia preferenza per Plus rispetto a Aggiungi alla domanda. Gradirei commenti su tale ragionamento. Sono davvero aperto all'idea di essere sciocco.
Jon Skeet,

@JaredPar: E se il tipo si chiama TestSuite però?
Jon Skeet,

Mi piacerebbe dare un altro +1 per la modifica 3, ma ovviamente no. (Nel mio caso non sto cercando di ottenere parallelismo - credo che l'immutabilità porti a un codice che è più facile ragionare.) Non sono ancora del tutto convinto che Aggiungi sia la strada da percorrere, ma il supporto per le risposte qui è persuasivo.
Jon Skeet,

Se ti capita di lasciare cadere questa domanda nella conversazione sul lavoro, sarebbe fantastico, tra l'altro. Ho iniziato la discussione su un elenco C #, quindi alcuni colleghi potrebbero già essere coinvolti. Potrei chiedere internamente anche a Google ...
Jon Skeet,

@Jon, penso di conoscere un buon posto per lasciare cadere questa domanda al lavoro :)
JaredPar,

27

Penso che questa possa essere una di quelle rare situazioni in cui è accettabile sovraccaricare l' +operatore. Nella terminologia matematica, sappiamo che +non aggiunge qualcosa alla fine di qualcos'altro. Combina sempre due valori insieme e restituisce un nuovo valore risultante.

Ad esempio, è intuitivamente ovvio che quando lo dici

x = 2 + 2;

il valore risultante di x è 4, non 22.

Allo stesso modo,

var empty = new ImmutableList<string>();
var list1 = empty + "Hello";
var list2 = list1 + "immutable";
var list3 = list2 + "word";

dovrebbe chiarire ciò che ogni variabile terrà. Dovrebbe essere chiaro che list2non è stato modificato nell'ultima riga, ma è invece list3assegnato il risultato dell'aggiunta della "parola" list2.

Altrimenti, vorrei solo nominare la funzione Plus ().


Cosa succede se si dispone di un elenco generico, al quale è possibile aggiungere legittimamente un numero intero (ad esempio) o un altro elenco di numeri interi? Quindi questo uso di + entrerà in conflitto con la concatenazione.
finnw,

@finnw: non vedo il tuo punto. Con un elenco mi aspetterei sempre che + significhi append, sia che si aggiungano uno o più elementi.
Bill the Lizard,

4
Per un'API riutilizzabile, è una buona idea avere anche un metodo denominato, nel caso in cui qualcuno stia usando la tua classe da una lingua senza sovraccarico dell'operatore.
Neil,

"se stai aggiungendo uno o più elementi": cosa succede se si desidera aggiungere l'elenco come singolo elemento? cioè, [1] + 2 = [1,2]ma [1] + [2] = [1,[2]]. Quello che stai suggerendo è un comportamento incoerente. Questo è probabilmente il motivo per cui Python non ti consente di aggiungere un elemento in questo modo.
Aprire il

Bene, in un linguaggio tipicamente statico come C # puoi dire qual è il tipo di elementi dell'elenco, che sia un elenco di elenchi o un elenco di elementi, quindi puoi usare il tipo per decidere se aggiungere un elemento che è un elenco o concatenare le due liste.
Dobes Vandermeer,

22

Per essere il più chiaro possibile, potresti voler andare con il wordier CopyAndAddo qualcosa di simile.


Tuttavia, non tutte le raccolte immutabili richiedono una copia da aggiungere. Pensa agli alberi immutabili, hanno solo bisogno di un nuovo nodo e possono usare l'albero esistente come una foglia.
JaredPar,

A proposito, ho letto il tuo profilo, poi ho invecchiato in ordine e sono stato brevemente stupito da quanti anni avevi. Sanity è entrato in azione poco dopo.
JaredPar,

Per il primo commento: uso alberi così raramente che quel pensiero non mi è mai venuto in mente. Questo è un buon punto.
Michael Myers

Secondo commento: lo confesso, l'ho fatto per il badge! Non mi piace dare la mia età. (In realtà sono più giovane di te, ma posso suonare il vecchio crotchety abbastanza bene se ne ho bisogno. E non sono l'unico la cui età è elencata come 89.)
Michael Myers

L'argomento alberi immutabili è forte, buon punto. Quindi EquivalentReferenceWithAdded (x) avrebbe combattuto quell'argomento, ma sembrava stupido e difficile da dedurre.
TheBlastOne,

21

Lo chiamerei Extend () o forse ExtendWith () se ti senti davvero prolisso.

Estendere significa aggiungere qualcosa a qualcos'altro senza cambiarlo. Penso che questa sia una terminologia molto rilevante in C # poiché è simile al concetto di metodi di estensione: essi "aggiungono" un nuovo metodo a una classe senza "toccare" la classe stessa.

Altrimenti, se vuoi davvero sottolineare che non modifichi affatto l'oggetto originale, usare un prefisso come Get- mi sembra inevitabile.


1
Un po 'implica comunque fare qualcosa all'oggetto base.
caos,

18

Aggiunto (), aggiunto ()

Mi piace usare il tempo passato per operazioni su oggetti immutabili. Trasmette l'idea che non stai cambiando l'oggetto originale ed è facile riconoscerlo quando lo vedi.

Inoltre, poiché i nomi dei metodi mutanti sono spesso verbi al presente, si applica alla maggior parte dei casi immutabili di nome metodo necessario che si verificano. Ad esempio uno stack immutabile ha i metodi "pushed" e "popped".


1
Anche Python usa questa convenzione. Ad esempio, le funzioni integrate invertite () e ordinate ().
Joe,

18

Mi piace il suggerimento di mmyer di CopyAndAdd . In linea con un tema di "mutazione", forse potresti scegliere Bud (riproduzione asessuata), crescere , replicare o evolvere ? =)

EDIT: Per continuare con il mio tema genetico, che ne è di Procreate , sottintendendo che viene creato un nuovo oggetto che si basa su quello precedente, ma con qualcosa di nuovo aggiunto.


14

Questo è probabilmente un tratto, ma in Ruby c'è una notazione comunemente usata per la distinzione: addnon muta; add!muta. Se questo è un problema pervasivo nel tuo progetto, potresti farlo anche tu (non necessariamente con caratteri non alfabetici, ma usando costantemente una notazione per indicare metodi di mutazione / non mutazione).


+1. questo non è applicato dalla lingua, ma concordato come una convenzione. Mi piace.
oma


13

Forse la confusione deriva dal fatto che si vogliono due operazioni in una. Perché non separarli? Stile DSL:

var list = new ImmutableList<string>("Hello");
var list2 = list.Copy().With("World!");

Copyrestituirebbe un oggetto intermedio, ovvero una copia mutabile dell'elenco originale. Withrestituirebbe un nuovo elenco immutabile.

Aggiornare:

Ma avere una collezione intermedia e mutevole non è un buon approccio. L'oggetto intermedio dovrebbe essere contenuto Copynell'operazione:

var list1 = new ImmutableList<string>("Hello");
var list2 = list1.Copy(list => list.Add("World!"));

Ora l' Copyoperazione richiede un delegato, che riceve un elenco modificabile, in modo che possa controllare l'esito della copia. Può fare molto di più che aggiungere un elemento, come rimuovere elementi o ordinare l'elenco. Può anche essere utilizzato nel ImmutableListcostruttore per assemblare l'elenco iniziale senza elenchi immutabili intermedi.

public ImmutableList<T> Copy(Action<IList<T>> mutate) {
  if (mutate == null) return this;
  var list = new List<T>(this);
  mutate(list);
  return new ImmutableList<T>(list);
}

Ora non c'è possibilità di interpretazioni errate da parte degli utenti, che cadranno naturalmente nella fossa del successo .

Ancora un altro aggiornamento:

Se non ti piace ancora la menzione dell'elenco mutabile, anche ora che è contenuta, puoi progettare un oggetto di specifica, che specificherà , o script , come l'operazione di copia trasformerà il suo elenco. L'utilizzo sarà lo stesso:

var list1 = new ImmutableList<string>("Hello");
// rules is a specification object, that takes commands to run in the copied collection
var list2 = list1.Copy(rules => rules.Append("World!"));

Ora puoi essere creativo con i nomi delle regole e puoi solo esporre la funzionalità che vuoi Copysupportare, non le intere funzionalità di un IList.

Per l'utilizzo del concatenamento, puoi creare un costruttore ragionevole (che ovviamente non utilizzerà il concatenamento):

public ImmutableList(params T[] elements) ...

...

var list = new ImmutableList<string>("Hello", "immutable", "World");

O usa lo stesso delegato in un altro costruttore:

var list = new ImmutableList<string>(rules => 
  rules
    .Append("Hello")
    .Append("immutable")
    .Append("World")
);

Ciò presuppone che il rules.Appendmetodo ritorni this.

Ecco come sarebbe con il tuo ultimo esempio:

var suite = new TestSuite<string, int>(x => x.Length);
var otherSuite = suite.Copy(rules => 
  rules
    .Append(x => Int32.Parse(x))
    .Append(x => x.GetHashCode())
);

@Jordao: Perché questo tipo di composizione porta a una forma di inizializzazione molto più semplice. Perché ho due variabili separate quando ne voglio solo una? Allo stesso modo, non voglio creare una copia mutabile, voglio che tutto sia immutabile, poiché ciò porta a un codice che è più facile da ragionare, IMO.
Jon Skeet,

Tutti questi sono ancora piuttosto ingombranti rispetto a "Plus" ecc. Grazie per le idee che riguardano la mutazione, ma preferisco decisamente l'approccio del "mantenerlo immutabile".
Jon Skeet,

Forse allora ci saranno sempre delle interpretazioni errate su quale sia la vera semantica dell'operazione. Se segui il percorso dell'oggetto della specifica, non si verifica alcuna mutazione (almeno non esternamente), l'oggetto specifica solo come apparirà il nuovo oggetto immutabile. Quello che hai è un'operazione che va da un oggetto immutabile all'altro, e dal momento che si chiama Copia, non c'è spazio per incomprensioni.
Jordão,

Gli unici nomi che potrebbero funzionare per te sembrano essere nomi composti, come CopyAndAppend, CopyAndAdd, ecc.
Jordão,

1
In realtà sto diventando sempre più affezionato a questo approccio (con tutte le modifiche) come API per raccolte immutabili. Tuttavia, direi che combinare questo approccio con i metodi helper per le specifiche predefinite, come Concat, offre il meglio di entrambi i mondi.
canapa

11

Alcuni pensieri casuali:

  • ImmutableAdd ()
  • Aggiungere()
  • Costruttore ImmutableList <T> (ImmutableList <T> originalList, T newItem)

1
+1 per ImmutableAdd; non mi piace aggiungere (troppo come StringBuilder.Append che sta mutando) e la versione del costruttore è una seccatura in termini di concatenamento.
Jon Skeet,

10

DateTime in C # usa Aggiungi. Quindi perché non usare lo stesso nome? Finché gli utenti della tua classe capiscono che la classe è immutabile.


Direi che DateTime.Add è noto per confondere le persone ... ma sono d'accordo che mostra la precedenza.
Jon Skeet,

1
Proprio come i metodi per mutare una stringa sono fonte di confusione per i nuovi sviluppatori. Ma presto tutti imparano che "le stringhe sono immutabili"
Tundey,

9

Penso che la cosa chiave a cui stai cercando di ottenere che sia difficile da esprimere sia la non-valutazione, quindi forse qualcosa con una parola generativa, qualcosa come CopyWith () o InstancePlus ().


9

Non penso che la lingua inglese ti permetta di implicare l'immutabilità in modo inconfondibile mentre usi un verbo che significa la stessa cosa di "Aggiungi". "Plus" lo fa quasi, ma le persone possono ancora fare l'errore.

L'unico modo per impedire agli utenti di confondere l'oggetto con qualcosa di mutabile è renderlo esplicito, sia attraverso il nome dell'oggetto stesso o attraverso il nome del metodo (come con le opzioni dettagliate come "GetCopyWith" o "CopyAndAdd").

Quindi vai con il tuo preferito "Plus".


9

Innanzitutto, un interessante punto di partenza: http://en.wikipedia.org/wiki/Naming_conventions_(programming) ... In particolare, controlla i link "Vedi anche" in basso.

Sono a favore di Plus o And, effettivamente ugualmente.

Plus ed And sono entrambi basati sulla matematica in etimologia. Come tale, entrambi connotano operazioni matematiche; entrambi producono un'espressione che legge naturalmente come espressioni che possono risolversi in un valore, che si adatta al metodo che ha un valore di ritorno. Andporta una connotazione logica aggiuntiva, ma entrambe le parole si applicano intuitivamente agli elenchi. Addconnota l'azione eseguita su un oggetto, che è in conflitto con l'immutabile semantica del metodo.

Entrambi sono brevi, il che è particolarmente importante data la primitività dell'operazione. Le operazioni semplici eseguite di frequente meritano nomi più brevi.

Esprimere la semantica immutabile è qualcosa che preferisco fare tramite il contesto. Cioè, preferirei semplicemente implicare che l'intero blocco di codice ha un aspetto funzionale; supponiamo che tutto sia immutabile. Potrei essere io, comunque. Preferisco che l'immutabilità sia la regola; se è fatto, è fatto molto nello stesso posto; la mutabilità è l'eccezione.


8

Che ne dici di Chain () o Attach ()?


1
Attaccare sicuramente suona come essere in mutazione. Forse WithAttached sarebbe più saggio, ma è molto vicino a WithAdded, che è stato discusso in precedenza.
TheBlastOne,

È divertente quante volte si parla di "concatenamento" nel descrivere cosa si sta tentando di fare. (5 volte), ma non offerto come suggerimento! È la prima cosa che mi è venuta in mente visualthesaurus.com(nessuna affiliazione) quando ho cercato concatenate.
cod3monk3y,

7

Preferisco Plus (e Meno). Sono facilmente comprensibili e mappano direttamente le operazioni che coinvolgono tipi immutabili ben noti (i numeri). 2 + 2 non cambia il valore di 2, restituisce un nuovo valore, altrettanto immutabile.

Alcune altre possibilità:

Splice ()

Corruzione()

Accrete ()


6

Che ne dici di mate , mateWith o coitus , per coloro che rimangono. In termini di riproduzione dei mammiferi sono generalmente considerati immutabili.

Andiamo a buttare fuori anche Union . Preso in prestito da SQL.


2
+1 per l'Unione. Tuttavia, lo prendo in prestito direttamente dalla teoria degli insiemi. :-)
Christoffer Lette,

SQL non ottiene gran parte della sua terminologia dalla teoria degli insiemi?
Jason D,

1
Inoltre, Union implica distinzione. Se si desidera includere duplicati (almeno in TSQL), è necessario utilizzare Union All in modo esplicito.
canapa,

6

Apparentemente sono la prima persona Obj-C / Cocoa a rispondere a questa domanda.

NNString *empty = [[NSString alloc] init];
NSString *list1 = [empty stringByAppendingString:@"Hello"];
NSString *list2 = [list1 stringByAppendingString:@"immutable"];
NSString *list3 = [list2 stringByAppendingString:@"word"];

Con questo non vincerò nessun gioco di golf con codice.


+1 il [object]By[Verb]ing[Object]:prefisso per il metodo implica che verrà restituita una nuova stringa anziché semplicemente [verb][Object]:, il che cambierebbe l'oggetto sul posto.
Dave DeLong,

3
+1. Non capisco l'avversione della gente alla verbosità (alias autocertificazione).
tratteggio

5

Penso che "Aggiungi" o "Plus" suona bene. Il nome dell'elenco stesso dovrebbe essere sufficiente per comunicare l'immutabilità dell'elenco.


Non è un elenco, è una suite di test.
Tstenner,

5

Forse ci sono alcune parole che mi ricordano più di aver fatto una copia e di aggiungere cose a quella invece di mutare l'istanza (come "Concatenare"). Ma penso che avere una certa simmetria per quelle parole per altre azioni sarebbe bello avere anche. Non conosco una parola simile per "Rimuovi" che penso dello stesso tipo di "Concatenare". "Plus" mi suona un po 'strano. Non mi aspetto che venga utilizzato in un contesto non numerico. Ma ciò potrebbe anche provenire dal mio background non inglese.

Forse avrei usato questo schema

AddToCopy
RemoveFromCopy
InsertIntoCopy

Questi hanno i loro problemi però, quando ci penso. Si potrebbe pensare che rimuovano qualcosa o aggiungano qualcosa a un argomento dato. Non ne sono affatto sicuro. Penso che quelle parole non giochino neanche nel concatenarsi. Troppo prolisso per scrivere.

Forse userei semplicemente "Aggiungi" e anche gli amici. Mi piace come viene usato in matematica

Add 1 to 2 and you get 3

Bene, certamente, un 2 rimane un 2 e ottieni un nuovo numero. Si tratta di due numeri e non di un elenco e un elemento, ma penso che abbia qualche analogia. Secondo me, addnon significa necessariamente che muti qualcosa. Sicuramente vedo il tuo punto che avere una dichiarazione solitaria contenente solo un adde non usare il nuovo oggetto restituito non sembra buggy. Ma ora ho anche pensato un po 'di tempo a quell'idea di usare un nome diverso da "aggiungi" ma non riesco proprio a trovare un altro nome, senza farmi pensare "hmm, avrei bisogno di consultare la documentazione per sapere cosa si tratta di "perché il suo nome differisce da quello che mi aspetterei di essere chiamato" aggiungi ". Solo qualche strano pensiero su questo da litb, non sono sicuro che abbia senso :)


Ma una copia non è sempre necessaria in una collezione immutabile. Prendi ad esempio un albero binario. L'aggiunta di una nuova radice non richiede copia, ma solo un nuovo valore in cui una delle foglie è il vecchio albero
JaredPar,

KISS - Se i nomi iniziassero a includere dettagli di implementazione, tutti i nomi dei metodi diventerebbero troppo lunghi. "aggiungi" è abbastanza semplice e fa il lavoro.
mP.

1
@mP: Ancora una volta usi la frase "dettagli di implementazione" in un modo che ritengo inadatto. Che si tratti di un elenco collegato o di un array sotto il cofano, è un dettaglio di implementazione . Potrei cambiare l' implementazione senza cambiare l'API. L'aspetto immutabile non è un dettaglio di implementazione.
Jon Skeet,

1
giusto. JaredPar, ma penso anche che non sia importante se in realtà copia l'albero o usa semplicemente l'albero esistente e lo usa come una foglia per il nuovo albero restituito. Voglio dire, questo è solo un dettaglio di implementazione. è lo stesso per (credo) l'operazione di sottostringa per la classe di stringhe di Java.
Johannes Schaub -


5

Penso che Plus()e Minus()o, in alternativa Including(), Excluding()siano ragionevoli a implicare un comportamento immutabile.

Tuttavia, nessuna scelta di denominazione lo renderà mai perfettamente chiaro a tutti, quindi credo personalmente che un buon commento sul documento xml andrebbe molto lontano qui. VS ti lancia questi in faccia quando scrivi il codice nell'IDE: sono difficili da ignorare.


4

Append- perché, nota che i nomi dei System.Stringmetodi suggeriscono che mutano l'istanza, ma non lo fanno.

O mi piace abbastanza AfterAppending:

void test()
{
  Bar bar = new Bar();
  List list = bar.AfterAppending("foo");
}

Come l'argomento DateTime in precedenza, sarei d'accordo con la precedenza se non fosse per il fatto che così tanti programmatori si aspettano che i metodi stringa facciano cose. Devono essere detti (a volte ripetutamente) che le stringhe sono immutabili. Vorrei attirare i miei sviluppatori client nella fossa del successo :)
Jon Skeet,

Mi piace aggiungere sempre di più. Si distingue che non stai mutando la collezione ma ti stai unendo ad essa.

4

list.CopyWith(element)

Come fa Smalltalk :)

Inoltre, list.copyWithout(element)ciò rimuove tutte le occorrenze di un elemento, che è molto utile quando viene utilizzato list.copyWithout(null)per rimuovere elementi non impostati.


3

Vorrei aggiungere Add, perché posso vedere il vantaggio di un nome migliore, ma il problema sarebbe quello di trovare nomi diversi per ogni altra operazione immutabile che potrebbe rendere la classe abbastanza sconosciuta se ciò ha senso.


Sì, vedo il tuo punto. Penso di preferire ancora Plus, ma vale la pena considerare.
Jon Skeet,

Grazie Jon. Non vedo l'ora di usare il tuo framework. Ho appena letto e sembra molto buono. Grazie ancora.
Joan Venge,
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.