Qual é o melhor nome para um método "add" não mutante em uma coleção imutável?

229

Desculpe pelo título waffly - se eu pudesse criar um título conciso, não precisaria fazer a pergunta.

Suponha que eu tenha um tipo de lista imutável. Possui uma operação Foo(x)que retorna uma nova lista imutável com o argumento especificado como um elemento extra no final. Então, para criar uma lista de strings com os valores "Hello", "immutable", "world", você pode escrever:

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

(Este é um código C #, e eu estou mais interessado em uma sugestão de C # se você achar que o idioma é importante. Não é fundamentalmente uma questão de idioma, mas os idiomas do idioma podem ser importantes.)

O importante é que as listas existentes não sejam alteradas por Foo- portanto empty.Count, ainda retornaria 0.

Outra maneira (mais idiomática) de chegar ao resultado final seria:

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

Minha pergunta é: qual é o melhor nome para Foo?

EDIÇÃO 3 : Como revelo mais adiante, o nome do tipo pode não ser realmente ImmutableList<T>, o que torna a posição clara. Imagine, ao contrário, que é TestSuitee é imutável, porque toda a estrutura da qual faz parte é imutável ...

(Fim da edição 3)

Opções que eu vim até agora:

  • Add: comum no .NET, mas implica em mutação da lista original
  • Cons: Acredito que esse seja o nome normal nas linguagens funcionais, mas sem sentido para quem não tem experiência nessas linguagens
  • Plus: meu favorito até agora, não implica mutação para mim . Aparentemente, isso também é usado no Haskell, mas com expectativas ligeiramente diferentes (um programador do Haskell pode esperar que ele adicione duas listas juntas em vez de adicionar um único valor à outra lista).
  • With: consistente com algumas outras convenções imutáveis, mas não possui a mesma "adição" à IMO.
  • And: não muito descritivo.
  • Sobrecarga de operador para +: eu realmente não gosto muito disso; Em geral, acho que os operadores devem ser aplicados apenas aos tipos de nível inferior. Estou disposto a ser persuadido!

Os critérios que estou usando para escolher são:

  • Dá a impressão correta do resultado da chamada do método (ou seja, é a lista original com um elemento extra)
  • Torna o mais claro possível que não altera a lista existente
  • Parece razoável quando encadeados, como no segundo exemplo acima

Por favor, peça mais detalhes se eu não estiver me esclarecendo o suficiente ...

EDIT 1: Aqui está meu raciocínio para preferir Plusa Add. Considere estas duas linhas de código:

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

Na minha opinião (e isso é uma coisa pessoal), o último é claramente buggy - é como escrever "x + 5;" como uma declaração por si só. A primeira linha parece estar correta, até você lembrar que é imutável. De fato, a maneira como o operador plus por si só não muda seus operandos é outra razão pela qual Plusé o meu favorito. Sem a ligeira repugnância da sobrecarga do operador, ela ainda fornece as mesmas conotações, que incluem (para mim) não alterar os operandos (ou o destino do método neste caso).

EDIT 2: Motivos para não gostar Adicionar.

Várias respostas são efetivamente: "Vá com Add. É isso que DateTimefaz, e Stringtem Replacemétodos etc. que não tornam a imutabilidade óbvia". Eu concordo - há precedência aqui. No entanto, tenho visto muitas pessoas chamam DateTime.Addou String.Replacee esperar mutação . Há muitas perguntas de grupos de notícias (e provavelmente SO, se eu procurar) que são respondidas por "Você está ignorando o valor de retorno String.Replace; strings são imutáveis, uma nova string é retornada".

Agora, devo revelar uma sutileza à pergunta - o tipo pode não ser realmente uma lista imutável, mas um tipo imutável diferente. Em particular, estou trabalhando em uma estrutura de benchmarking em que você adiciona testes a um conjunto e isso cria um novo conjunto. Pode ser óbvio que:

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

não vai conseguir nada, mas fica muito mais obscuro quando você o altera para:

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

Parece que tudo ficará bem. Enquanto isso, para mim, torna o erro mais claro:

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

Isso está apenas implorando para ser:

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

Idealmente, eu gostaria que meus usuários não precisassem saber que o conjunto de testes é imutável. Eu quero que eles caiam no poço do sucesso. Isso pode não ser possível, mas eu gostaria de tentar.

Peço desculpas por simplificar demais a pergunta original falando apenas sobre um tipo de lista imutável. Nem todas as coleções são tão auto-descritivas quanto ImmutableList<T>:)

Jon Skeet
fonte
2
@ Adam: Não, o último é claramente de buggy. Na verdade, os dois estão de buggy (como não estão fazendo nada com o resultado) - mas o primeiro não me parece de buggy.
9139 Jon Skeet
36
Um uncat é um cachorro?
Michael Myers
7
Concat / Condog ... funciona para mim! ;)
gnovice
11
Uncat - isso seria um gato zumbi.
21411 Erik Forbes
2
@ Trap: Isso é péssimo em termos de tornar a API fluida.
Jon Skeet

Respostas:

130

Em situações como essa, eu costumo ir junto Concat. Isso geralmente implica para mim que um novo objeto está sendo criado.

var p = listA.Concat(listB);
var k = listA.Concat(item);
MojoFilter
fonte
3
É isso que eu uso, porque é o que System.Linq.Enumerable usa - a decisão já está tomada. :) Não posso ser a única pessoa que definiu sua própria sobrecarga da extensão Concat no IEnumerable para aceitar um único valor a ser acrescentado.
21119 Daniel Earwicker
9
+1 Esta é a resposta correta para manter a consistência de nomes na estrutura.
Sam Harwell
A menos que eu esteja sentindo falta, o System.Linq.Enumerable (e o Linq em geral) só usa Concat () para "sequência + sequência", nunca "item + sequência". O problema que alguém "pode ​​esperar que adicione duas listas juntas em vez de adicionar um único valor à outra lista" foi explicitamente apresentado como um motivo para não usar uma das outras opções originais.
precisa saber é o seguinte
119

Eu iria com Contras, por uma simples razão: significa exatamente o que você deseja.

  1. Sou um grande fã de dizer exatamente o que quero dizer, especialmente no código fonte. Um novato terá que procurar a definição de Contras apenas uma vez, mas depois ler e usar isso mil vezes. Acho que, a longo prazo, é melhor trabalhar com sistemas que facilitam o caso comum, mesmo que o custo inicial seja um pouco maior.

  2. O fato de que seria "sem sentido" para pessoas sem experiência em FP é realmente uma grande vantagem. Como você apontou, todas as outras palavras que você encontrou já têm algum significado, e esse significado é um pouco diferente ou ambíguo. Um novo conceito deve ter uma nova palavra (ou, neste caso, uma antiga). Prefiro que alguém tenha que procurar a definição de Contras, do que assumir incorretamente que sabe o que Add faz.

  3. Outras operações emprestadas de linguagens funcionais geralmente mantêm seus nomes originais, sem catástrofes aparentes. Não vi nenhum esforço para sugerir sinônimos para "map" e "reduzir" que soam mais familiares aos não-jogadores de FPP, nem vejo nenhum benefício em fazê-lo.

(Divulgação completa: eu sou um programador Lisp, então já sei o que Contras significa.)

Ken
fonte
16
Não esqueça que a descoberta é importante - se eu digitar "testSuite". e veja a lista de métodos, gostaria de ver um método que sugira a coisa certa. Provavelmente não vou procurar um nome sem sentido (para mim) por acaso é o que eu quero.
9139 Jon Skeet
33
Se eu estivesse me sentindo mal-humorado, criaria um método Add que simplesmente gerou uma exceção com a mensagem = "Use Contras para anexar um ImmutableList". :-)
Ken
2
Não vai matar ninguém ler algumas linhas de comentários, explicando o porquê do nome e referindo-as, digamos, à "Estrutura e Interpretação de Programas de Computador" de Abelson & Sussman.
John R. Strohm
16
Tradicionalmente, os contras aumentam no começo e não no final. Portanto, é um nome potencialmente enganoso para o método descrito.
precisa saber é o seguinte
16
Apenas para salvar o próximo programador não funcional com um clique ou 3 ... en.wikipedia.org/wiki/Cons da palavra "construct", a expressão "cons x em y" significa construir um novo objeto com ( contras xy)
Myster 26/05
59

Na verdade, eu gosto And, especialmente da maneira idiomática. Eu gostaria especialmente se você tivesse uma propriedade estática somente leitura para a lista Vazia e talvez torne o construtor privado, para que você sempre precise construir a partir da lista vazia.

var list = ImmutableList<string>.Empty.And("Hello")
                                      .And("Immutable")
                                      .And("Word");
tvanfosson
fonte
Eu gosto da ideia Vazia. Ainda não está convencido sobre E embora. É apenas um pouco blá.
9139 Jon Skeet
Parece mais como eu pensaria em construir uma lista de coisas em linguagem natural. Se você ler em voz alta, parecerá mais intuitivo do que o Add ou Plus. "lista" é a lista vazia e "Olá" e "Imutável" e "Word". Eu concordaria que é menos claro isoladamente.
23410 tvanfosson
52

Sempre que estou com uma nomenclatura, bato nas interwebs.

thesaurus.com retorna isso para "add":

Definição: juntar, aumentar; faça mais comentários

Sinônimos: afixar, anexar, ante, anexar, aumentar, reforçar, aumentar, acumular, cobrar, continuar, dar entrada, figura dentro, carne para fora, esquentar, caminhar, caminhar, caminhar, engate, engate, engate com, inclua, jack up, jazz up, junte-se, pad, parlay, nas costas, conecte, despeje, responda, suba, diga mais, bofetada, bola de neve, sopa, acelere, pique, intensifique, suplemento, adoçar, aderência, etiqueta

Eu gosto do som Adjoin, ou mais simplesmente Join. É isso que você está fazendo, certo? O método também pode se aplicar à união de outros ImmutableList<>.

Spoulson
fonte
1
Eu meio que gosto de 'Join' também, mas, na maioria dos casos, quando você junta dois objetos, você termina com 1. Nesse caso, se você juntar dois objetos, estará criando um novo objeto.
Outlaw Programmer
1
Não conheço nenhum caso em .NET, Perl, PHP ou mesmo VBScript em que Join implique mutação. O design é tal que A e B se unem para criar C, onde C é sempre uma nova entidade.
Spoulson 06/02/09
Gosto de Participar e concordo totalmente com o thesaurus.com :) Use-o o tempo todo em caso de dúvida sobre um nome.
21430 Skurmedel
var suite = novo TestSuite <string, int> () .Join (x => x.Length);
Sly Gryphon
3
Vá com Piggyback, imo. Ou HookUpWith.
Chris Marasti-Georg
48

Pessoalmente, eu gosto de .With (). Se eu estivesse usando o objeto, depois de ler a documentação ou os comentários do código, seria claro o que ele faz e ele lê ok no código-fonte.

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

Ou você adiciona "Junto" com ele .. :)

object.AlongWith("this new item");
LarryF
fonte
+1. "WITH" é um operador infix no SETL que faz a mesma coisa. Se usos SETL ele, então ele deve estar certo :-)
finnw
1
Bah ... Quem usa mais o VB? :) Uh .. Opps .. Isso foi em voz alta? heh .. Mas, não, com toda a seriedade, é por isso que considerei o "AlongWith", que removeria o problema do VB. Existem apenas cerca de um milhão de maneiras diferentes de ele usar essa ... Quero dizer, mesmo as loucas como: object.Plus () ou Object.ExistingPlus () ... etc ... É uma pergunta muito boa que ele publicado, no entanto ... heh ..
LarryF 24/11/2009
33

Acabei indo com Add para todas as minhas coleções imutáveis ​​no BclExtras . A razão é que é um nome fácil e previsível. Não estou preocupado tanto com as pessoas que confundem Add com um add mutante, já que o nome do tipo é prefixado com Immutable.

Por um tempo, considerei Contras e outros nomes de estilos funcionais. Eventualmente, eu os descontei porque eles não são tão conhecidos. Certamente os programadores funcionais entenderão, mas não são a maioria dos usuários.

Outros nomes: você mencionou:

  • Plus: Eu estou com vontade / lavando este. Para mim, isso não a distingue como uma operação sem mutação, mais do que Add
  • With: Causará problemas com o VB (trocadilho intencional)
  • Sobrecarga do operador: a descoberta seria um problema

Opções que eu considerei:

  • Concat: String é imutável e use isso. Infelizmente só é realmente bom para adicionar até o final
  • CopyAdd: Copie o que? A fonte, a lista?
  • AddToNewList: Talvez seja bom para a Lista. Mas e quanto a uma coleção, pilha, fila, etc ...

Infelizmente, não parece realmente haver uma palavra que seja

  1. Definitivamente uma operação imutável
  2. Compreensível para a maioria dos usuários
  3. Representável em menos de 4 palavras

Fica ainda mais estranho quando você considera coleções diferentes de Lista. Tomemos, por exemplo, Stack. Mesmo os programadores do primeiro ano podem dizer que o Stacks tem um par de métodos Push / Pop. Se você criar um ImmutableStack e der um nome completamente diferente, vamos chamá-lo de Foo / Fop, você adicionou mais trabalho para eles usarem sua coleção.

Editar: Resposta ao Plus Edit

Eu vejo para onde você está indo com o Plus. Eu acho que um caso mais forte seria, na verdade, Minus para remoção. Se eu visse o seguinte, certamente me perguntaria o que no mundo o programador estava pensando.

list.Minus(obj);

O maior problema que tenho com o Plus / Minus ou com um novo emparelhamento é como um exagero. A coleção em si já tem um nome distinto, o prefixo Imutável. Por que ir além, adicionando vocabulário cuja intenção é adicionar a mesma distinção que o prefixo Imutável já fez.

Eu posso ver o argumento do site de chamada. Isso torna mais claro do ponto de vista de uma única expressão. Mas, no contexto de toda a função, parece desnecessário.

Editar 2

Concorde que as pessoas definitivamente ficaram confusas com String.Concat e DateTime.Add. Eu já vi vários programadores muito brilhantes acertarem esse problema.

No entanto, acho que ImmutableList é um argumento diferente. Não há nada sobre String ou DateTime que o estabeleça como Imutável para um programador. Você deve simplesmente saber que é imutável por meio de outra fonte. Portanto, a confusão não é inesperada.

ImmutableList não tem esse problema porque o nome define seu comportamento. Você poderia argumentar que as pessoas não sabem o que é imutável e acho que isso também é válido. Eu certamente não sabia disso até o segundo ano da faculdade. Mas você tem o mesmo problema com o nome que escolher, em vez de Adicionar.

Edit 3: E quanto a tipos como o TestSuite que são imutáveis, mas não contêm a palavra?

Eu acho que isso leva à ideia de que você não deveria inventar novos nomes de métodos. Ou seja, porque há claramente uma unidade para tornar os tipos imutáveis, a fim de facilitar operações paralelas. Se você se concentrar em alterar o nome dos métodos para coleções, a próxima etapa será a mutação dos nomes dos métodos em todos os tipos que você usar que sejam imutáveis.

Eu acho que seria um esforço mais valioso focar em tornar os tipos identificáveis ​​como Imutáveis. Dessa forma, você pode resolver o problema sem repensar todos os padrões de métodos mutantes existentes.

Agora, como você pode identificar o TestSuite como imutável? No ambiente de hoje, acho que existem algumas maneiras

  1. Prefixo com Immutable: ImmutableTestSuite
  2. Adicione um atributo que descreva o nível de imutabilidade. Isso é certamente menos detectável
  3. Não há muito mais.

Meu palpite / esperança é que as ferramentas de desenvolvimento começarão a ajudar esse problema, facilitando a identificação de tipos imutáveis ​​simplesmente pela visão (cor diferente, fonte mais forte, etc ...). Mas acho que essa é a resposta, porém, sobre a alteração de todos os nomes de métodos.

JaredPar
fonte
Adicionei motivos para a minha preferência pelo Plus sobre Adicionar à pergunta. Gostaria de receber comentários sobre esse raciocínio. Estou realmente aberto à ideia de que estou sendo bobo.
9139 Jon Skeet
@JaredPar: E se o tipo for chamado TestSuite?
9139 Jon Skeet
Gostaria de dar outro +1 para a edição 3, mas obviamente não pode. (No meu caso, não estou tentando obter paralelismo - acredito que a imutabilidade leva a códigos mais fáceis de raciocinar.) Ainda não estou totalmente convencido de que Add seja o caminho a seguir, mas o suporte para as respostas aqui é persuasivo.
9139 Jon Skeet
Se por acaso você colocar essa pergunta em uma conversa no trabalho, isso seria incrível também. Comecei a discussão em uma lista de C #, para que alguns colegas já possam estar envolvidos. Pode perguntar internamente na Google também ...
Jon Skeet
@ Jon, eu acho que sei um bom lugar para deixar esta questão no trabalho :)
JaredPar
27

Acho que essa pode ser uma daquelas situações raras em que é aceitável sobrecarregar o +operador. Na terminologia matemática, sabemos que +isso não acrescenta algo ao final de outra coisa. Sempre combina dois valores e retorna um novo valor resultante.

Por exemplo, é intuitivamente óbvio que quando você diz

x = 2 + 2;

o valor resultante de x é 4, não 22.

Similarmente,

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

deve deixar claro o que cada variável irá conter. Deve ficar claro que list2não foi alterado na última linha, mas ao invés disso list3é atribuído o resultado de anexar "palavra" a list2.

Caso contrário, eu apenas nomearia a função Plus ().

Bill, o Lagarto
fonte
E se você tiver uma lista genérica, à qual você poderia legitimamente adicionar um número inteiro (por exemplo) ou outra lista de números inteiros? Então, esse uso de + entrará em conflito com a concatenação.
finnw
@ Finnw: Eu não entendo o seu ponto. Com uma lista, eu sempre esperaria + significar acréscimo, esteja você adicionando um elemento ou muitos.
Bill Bill Lizard
4
Para uma API reutilizável, é uma boa idéia também ter um método nomeado, caso alguém esteja usando sua classe de um idioma sem sobrecarregar o operador.
214 Neil
"se você está adicionando um elemento ou muitos" - e se você quiser adicionar a lista como um único elemento? ou seja, [1] + 2 = [1,2]mas [1] + [2] = [1,[2]]. O que você está sugerindo é um comportamento inconsistente. É provavelmente por isso que o Python não permite adicionar um elemento dessa maneira.
MPEN
Bem, em uma linguagem digitada estaticamente como C #, você pode dizer qual é o tipo de elementos da lista, seja uma lista de listas ou uma lista de elementos, para que você possa usar o tipo para decidir se deseja adicionar um elemento que é uma lista ou concatenar as duas listas.
Dobes Vandermeer
22

Para ser o mais claro possível, convém usar o mais expressivo CopyAndAddou algo semelhante.

Michael Myers
fonte
Porém, nem todas as coleções imutáveis ​​exigem uma cópia para adicionar. Pense em árvores imutáveis, elas precisam apenas de um novo nó e podem usar a árvore existente como uma folha.
6119 JaredPar
BTW, li o seu perfil, depois envelheci em ordem e fiquei brevemente espantado com a sua idade. Sanidade entrou em ação logo depois.
6119 JaredPar
Primeiro comentário: uso árvores tão raramente que esse pensamento nunca me ocorreu. Essa é uma boa opinião.
Michael Myers
Re segundo comentário: confesso, fiz isso pelo distintivo! Só não gosto de dar a minha idade. (Na verdade, sou mais jovem que você, mas posso jogar muito bem com o velho, se precisar. E não sou o único com a idade de 89 anos.)
Michael Myers
O argumento das árvores imutáveis ​​é forte, bom ponto. Portanto, EquivalentReferenceWithAdded (x) combateria esse argumento, mas parece estúpido e difícil de deduzir.
TheBlastOne
21

Eu chamaria Extend () ou talvez ExtendWith () se você se sentir realmente detalhado.

Estende significa adicionar algo a algo sem alterá-lo. Eu acho que essa terminologia é muito relevante em C #, pois é semelhante ao conceito de métodos de extensão - eles "adicionam" um novo método a uma classe sem "tocar" a própria classe.

Caso contrário, se você realmente deseja enfatizar que não modifica o objeto original, usar um prefixo como Get- parece inevitável para mim.

DrJokepu
fonte
1
Ainda meio que implica fazer algo com o objeto base.
caos
18

Adicionado (), anexado ()

Eu gosto de usar o tempo passado para operações em objetos imutáveis. Ele transmite a ideia de que você não está alterando o objeto original e é fácil reconhecer quando o vê.

Além disso, como os nomes de métodos mutantes geralmente são verbos no tempo presente, isso se aplica à maioria dos casos necessários para o nome do método imutável nos quais você se depara. Por exemplo, uma pilha imutável tem os métodos "push" e "popped".

Strilanc
fonte
1
Python também usa essa convenção. Por exemplo, funções internas invertidas () e ordenadas ().
21410 Joe
18

Eu gosto de mmyers sugestão de CopyAndAdd . De acordo com o tema "mutação", talvez você possa usar Bud (reprodução assexuada), Crescer , Replicar ou Evoluir ? =)

EDIT: Para continuar com o meu tema genético, que tal Procreate , o que implica que um novo objeto é criado, baseado no anterior, mas com algo novo adicionado.

gnovice
fonte
14

Provavelmente é um exagero, mas em Ruby existe uma notação comum para a distinção: addnão muda; add!muda. Se esse é um problema generalizado em seu projeto, você também pode fazer isso (não necessariamente com caracteres não alfabéticos, mas usando consistentemente uma notação para indicar métodos de mutação / não mutação).

ykaganovich
fonte
+1. isso não é imposto pelo idioma, mas é acordado como uma convenção. Eu gosto disso.
Oma 17/05
13

Join parece apropriado.

ykaganovich
fonte
13

Talvez a confusão decorra do fato de que você deseja duas operações em uma. Por que não separá-los? Estilo DSL:

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

Copy retornaria um objeto intermediário, que é uma cópia mutável da lista original. Withretornaria uma nova lista imutável.

Atualizar:

Mas, ter uma coleção intermediária e mutável não é uma boa abordagem. O objeto intermediário deve estar contido na Copyoperação:

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

Agora, a Copyoperação recebe um delegado, que recebe uma lista mutável, para que possa controlar o resultado da cópia. Pode fazer muito mais do que acrescentar um elemento, como remover elementos ou classificar a lista. Também pode ser usado no ImmutableListconstrutor para montar a lista inicial sem listas imutáveis ​​intermediárias.

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);
}

Agora não há possibilidade de erros de interpretação por parte dos usuários, eles naturalmente cairão no poço do sucesso .

Mais uma atualização:

Se você ainda não gostar da menção à lista mutável, mesmo que ela esteja contida, é possível projetar um objeto de especificação, que especificará , ou script , como a operação de cópia transformará sua lista. O uso será o mesmo:

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!"));

Agora você pode ser criativo com os nomes das regras e só pode expor a funcionalidade que deseja Copyoferecer suporte, não todos os recursos de um IList.

Para o uso do encadeamento, você pode criar um construtor razoável (que não usará encadeamento, é claro):

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

...

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

Ou use o mesmo delegado em outro construtor:

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

Isso pressupõe que o rules.Appendmétodo retornethis .

É assim que seria com o seu exemplo mais recente:

var suite = new TestSuite<string, int>(x => x.Length);
var otherSuite = suite.Copy(rules => 
  rules
    .Append(x => Int32.Parse(x))
    .Append(x => x.GetHashCode())
);
Jordão
fonte
@ Jordao: Porque esse tipo de composição leva a uma forma de inicialização mais simples. Por que ter duas variáveis ​​separadas quando eu quero apenas uma? Da mesma forma, não quero criar uma cópia mutável - quero que tudo seja imutável o tempo todo, pois isso leva a códigos que são mais fáceis de raciocinar, IMO.
Jon Skeet
Tudo isso ainda é um pouco mais difícil do que o "Plus" etc. Obrigado pelas idéias que envolvem mutação, mas eu definitivamente prefiro a abordagem "manter imutável".
Jon Skeet
Talvez sempre haja interpretações errôneas sobre quais são as reais semânticas da operação. Se você seguir a rota do objeto de especificação, não haverá mutação (pelo menos não externamente), o objeto especificará apenas como será o novo objeto imutável. O que você tem é uma operação que vai de um objeto imutável para outro e, como é chamada Copiar, não há espaço para mal-entendidos.
Jordão
Os únicos nomes que funcionariam para você parecem ser nomes compostos, como CopyAndAppend, CopyAndAdd, etc.
Jordão
1
Na verdade, estou cada vez mais acostumado com essa abordagem (com todas as edições) como uma API para coleções imutáveis. No entanto, eu argumentaria que combinar essa abordagem com métodos auxiliares para especificações padrão, como o Concat, oferece o melhor dos dois mundos.
cânhamo
11

Alguns pensamentos aleatórios:

  • ImmutableAdd ()
  • Acrescentar()
  • Construtor ImmutableList <T> (ImmutableList <T> originalList, T newItem)
Chris Shaffer
fonte
1
+1 para ImmutableAdd; não gosta do Append (muito parecido com o StringBuilder.Append, que está em mutação) e a versão do construtor é um problema em termos de encadeamento.
9139 Jon Skeet
10

DateTime em C # usa Add. Então, por que não usar o mesmo nome? Desde que os usuários da sua classe entendam que a classe é imutável.

Tundey
fonte
Eu diria que o DateTime.Add é conhecido por confundir as pessoas ... mas eu concordo que mostra precedência.
9139 Jon Skeet
1
Assim como métodos para modificar uma string são confusos para novos desenvolvedores. Mas logo aprende a todos que "strings são imutáveis"
Tundey
9

Eu acho que a principal coisa que você está tentando entender que é difícil expressar é a não-permutação, então talvez algo com uma palavra generativa, algo como CopyWith () ou InstancePlus ().

caos
fonte
9

Eu não acho que o idioma inglês permita implantar imutabilidade de maneira inconfundível enquanto estiver usando um verbo que significa a mesma coisa que "Adicionar". O "Plus" quase faz isso, mas as pessoas ainda podem cometer o erro.

A única maneira de impedir que seus usuários confundam o objeto com algo mutável é explicitando-o pelo nome do próprio objeto ou pelo nome do método (como nas opções detalhadas, como "GetCopyWith" ou "CopyAndAdd").

Então, basta ir com o seu favorito "Plus".

Adam Bellaire
fonte
9

Primeiro, um ponto de partida interessante: http://en.wikipedia.org/wiki/Naming_conventions_(programming) ... Em particular, verifique os links "Consulte também" na parte inferior.

Sou a favor de Plus ou And, efetivamente igualmente.

Plus e And são baseados em matemática na etimologia. Como tal, ambos conotam operação matemática; ambos produzem uma expressão que lê naturalmente como expressões que podem se transformar em um valor, que se encaixa no método que tem um valor de retorno. Andtem conotação lógica adicional, mas ambas as palavras se aplicam intuitivamente a listas. Addconota a ação executada em um objeto, que entra em conflito com a semântica imutável do método.

Ambos são curtos, o que é especialmente importante, dada a primitividade da operação. Operações simples e freqüentemente executadas merecem nomes mais curtos.

Expressar semântica imutável é algo que prefiro fazer via contexto. Ou seja, eu prefiro simplesmente implicar que todo esse bloco de código tenha uma sensação funcional; assuma que tudo é imutável. Isso pode ser apenas eu, no entanto. Eu prefiro a imutabilidade ser a regra; se for feito, é feito muito no mesmo lugar; a mutabilidade é a exceção.

Paul Brinkley
fonte
8

Que tal Chain () ou Attach ()?

Webjedi
fonte
1
Anexar certamente parece estar mudando. Talvez WithAttached seja mais sensato, mas esteja muito próximo de WithAdded, que foi discutido acima.
TheBlastOne
É engraçado quantas vezes o "encadeamento" é mencionado na descrição do que está tentando ser feito com isso. (5 vezes), mas não é uma sugestão! É a primeira coisa que surgiu visualthesaurus.com(sem afiliação) quando procurei concatenate.
Cod3monk3y
7

Eu prefiro Plus (e Minus). Eles são facilmente compreensíveis e são mapeados diretamente para operações que envolvem tipos imutáveis ​​conhecidos (os números). 2 + 2 não altera o valor de 2, retorna um novo valor igualmente imutável.

Algumas outras possibilidades:

Emenda ()

Enxerto()

Acreditado ()

Wedge
fonte
6

Que tal companheiro , companheiro com , ou coito , para aqueles que permanecem. Em termos de reprodução, os mamíferos são geralmente considerados imutáveis.

Vai jogar Union lá fora também. Emprestado do SQL.

jason saldo
fonte
2
+1 para a União. Eu, no entanto, empresto-o diretamente da teoria dos conjuntos. :-)
Christoffer Lette
O SQL não obtém grande parte de sua terminologia da teoria dos conjuntos?
Jason D
1
Além disso, Union implica distinção. Se você deseja incluir duplicatas (pelo menos no TSQL), é necessário usar o Union All explicitamente.
cânhamo
6

Aparentemente, sou a primeira pessoa da Obj-C / Cocoa a responder a essa pergunta.

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

Não vai ganhar nenhum jogo de código de golfe com isso.

kubi
fonte
Marcar com +1 o [object]By[Verb]ing[Object]:prefixo do método implica que uma nova string será retornada, em vez de simplesmente [verb][Object]:, o que modificaria o objeto no local.
Dave DeLong
3
+1. Não entendo a aversão das pessoas à verbosidade (também conhecida como auto-documentação).
hatfinch
5

Eu acho que "Adicionar" ou "Mais" soa bem. O nome da lista em si deve ser suficiente para transmitir a imutabilidade da lista.

David Morton
fonte
Não é uma lista, é uma suíte de testes.
tstenner
5

Talvez existam algumas palavras que me lembrem mais de fazer uma cópia e adicionar coisas a isso em vez de alterar a instância (como "Concatenar"). Mas acho que ter simetria para essas palavras para outras ações também seria bom. Não conheço uma palavra semelhante para "Remover" que penso do mesmo tipo como "Concatenar". "Plus" parece um pouco estranho para mim. Eu não esperaria que fosse usado em um contexto não numérico. Mas isso também pode vir da minha formação em inglês.

Talvez eu usaria esse esquema

AddToCopy
RemoveFromCopy
InsertIntoCopy

Estes têm seus próprios problemas, porém, quando penso nisso. Pode-se pensar que eles removem algo ou acrescentam algo a um argumento dado. Não tenho certeza disso. Essas palavras também não são boas no encadeamento, eu acho. Muito prolixo para digitar.

Talvez eu usaria simplesmente "Adicionar" e amigos também. Eu gosto de como é usado em matemática

Add 1 to 2 and you get 3

Bem, certamente, um 2 permanece um 2 e você recebe um novo número. Trata-se de dois números e não de uma lista e um elemento, mas acho que tem alguma analogia. Na minha opinião, addnão significa necessariamente que você muda alguma coisa. Certamente, entendo que ter uma declaração solitária contendo apenas um adde não usar o novo objeto retornado não parece problemático. Mas agora eu também pensei um pouco sobre a ideia de usar outro nome que não seja "add", mas simplesmente não consigo criar outro nome, sem me fazer pensar "hmm, eu precisaria olhar a documentação para saber o que trata-se de "porque seu nome difere do que eu esperaria ser chamado de" adicionar ". Apenas um pensamento estranho sobre isso do litb, não tenho certeza se faz sentido :)

Johannes Schaub - litb
fonte
Mas uma cópia nem sempre é necessária em uma coleção imutável. Veja uma árvore binária, por exemplo. Adicionando uma nova raiz não requer nenhuma cópia, apenas um novo valor, onde uma das folhas é a árvore velha
JaredPar
BEIJO - Se a nomeação começasse a incluir detalhes da implementação, todos os nomes de métodos se tornariam excessivamente longos. "add" é bastante simples e faz o trabalho.
mP.
1
@ MP: Mais uma vez, você usa a frase "detalhes de implementação" de uma maneira que acredito ser inadequada. Seja uma lista vinculada ou uma matriz sob o capô, é um detalhe da implementação . Eu poderia mudar a implementação sem alterar a API. O aspecto imutável não é um detalhe de implementação.
9119 Jon Skeet
1
certo. JaredPar, mas acho que também não é importante se ele realmente copia a árvore ou apenas usa a árvore existente e a usa como uma folha para a nova árvore retornada. Quero dizer, isso é apenas um detalhe de implementação. é o mesmo para (acredito) a operação de substring para a classe string do java.
Johannes Schaub - litb 8/02/09
5

Eu acho que Plus()e Minus()ou, alternativamente Including(), Excluding()são razoáveis ​​em implicar comportamento imutável.

No entanto, nenhuma opção de nomenclatura deixará isso perfeitamente claro para todos, então eu pessoalmente acredito que um bom comentário em xml doc seria um longo caminho até aqui. O VS joga isso bem na sua cara quando você escreve código no IDE - é difícil ignorar.

LBushkin
fonte
4

Append - porque, observe que os nomes dos System.String métodos sugerem que eles mudam a instância, mas não o fazem.

Ou eu gosto bastante de AfterAppending:

void test()
{
  Bar bar = new Bar();
  List list = bar.AfterAppending("foo");
}
ChrisW
fonte
Como o argumento DateTime anteriormente, eu concordaria com a precedência se não fosse pelo fato de que muitos programadores que esperar métodos de string para fazer coisas. Eles precisam ser informados (às vezes repetidamente) de que as cordas são imutáveis. Eu gostaria de atrair os meus desenvolvedores de clientes no poço do sucesso :)
Jon Skeet
Eu gosto de acrescentar mais e mais. Distingue que você não está modificando a coleção, mas se associando a ela.
4

list.CopyWith(element)

Assim como o Smalltalk :)

E list.copyWithout(element)isso também remove todas as ocorrências de um elemento, o que é mais útil quando usado list.copyWithout(null)para remover elementos não configurados.

akuhn
fonte
3

Eu gostaria de adicionar, porque vejo o benefício de um nome melhor, mas o problema seria encontrar nomes diferentes para todas as outras operações imutáveis ​​que possam tornar a classe pouco familiar, se isso fizer sentido.

Joan Venge
fonte
Sim, entendo o seu ponto. Acho que ainda prefiro o Plus, mas vale a pena considerar.
21710 Jon Skeet
Obrigado Jon. Estou ansioso para usar sua estrutura. Acabei de ler sobre isso e parece muito bom. Obrigado novamente.
23611 Joan Venge