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 é TestSuite
e é 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 originalCons
: Acredito que esse seja o nome normal nas linguagens funcionais, mas sem sentido para quem não tem experiência nessas linguagensPlus
: 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 Plus
a 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 DateTime
faz, e String
tem Replace
métodos etc. que não tornam a imutabilidade óbvia". Eu concordo - há precedência aqui. No entanto, tenho visto muitas pessoas chamam DateTime.Add
ou String.Replace
e 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>
:)
fonte
Respostas:
Em situações como essa, eu costumo ir junto
Concat
. Isso geralmente implica para mim que um novo objeto está sendo criado.fonte
Eu iria com Contras, por uma simples razão: significa exatamente o que você deseja.
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.
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.
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.)
fonte
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.fonte
Sempre que estou com uma nomenclatura, bato nas interwebs.
thesaurus.com retorna isso para "add":
Eu gosto do som
Adjoin
, ou mais simplesmenteJoin
. É isso que você está fazendo, certo? O método também pode se aplicar à união de outrosImmutableList<>
.fonte
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.
Ou você adiciona "Junto" com ele .. :)
fonte
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:
Opções que eu considerei:
Infelizmente, não parece realmente haver uma palavra que seja
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.
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
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.
fonte
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
o valor resultante de x é 4, não 22.
Similarmente,
deve deixar claro o que cada variável irá conter. Deve ficar claro que
list2
não foi alterado na última linha, mas ao invés dissolist3
é atribuído o resultado de anexar "palavra" alist2
.Caso contrário, eu apenas nomearia a função Plus ().
fonte
[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.Para ser o mais claro possível, convém usar o mais expressivo
CopyAndAdd
ou algo semelhante.fonte
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.
fonte
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".
fonte
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.
fonte
Provavelmente é um exagero, mas em Ruby existe uma notação comum para a distinção:
add
nã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).fonte
Join
parece apropriado.fonte
Talvez a confusão decorra do fato de que você deseja duas operações em uma. Por que não separá-los? Estilo DSL:
Copy
retornaria um objeto intermediário, que é uma cópia mutável da lista original.With
retornaria 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
Copy
operação:Agora, a
Copy
operaçã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 noImmutableList
construtor para montar a lista inicial sem listas imutáveis intermediárias.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:
Agora você pode ser criativo com os nomes das regras e só pode expor a funcionalidade que deseja
Copy
oferecer suporte, não todos os recursos de umIList
.Para o uso do encadeamento, você pode criar um construtor razoável (que não usará encadeamento, é claro):
Ou use o mesmo delegado em outro construtor:
Isso pressupõe que o
rules.Append
método retornethis
.É assim que seria com o seu exemplo mais recente:
fonte
Alguns pensamentos aleatórios:
fonte
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.
fonte
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 ().
fonte
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".
fonte
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.
And
tem conotação lógica adicional, mas ambas as palavras se aplicam intuitivamente a listas.Add
conota 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.
fonte
Que tal Chain () ou Attach ()?
fonte
visualthesaurus.com
(sem afiliação) quando procureiconcatenate
.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 ()
fonte
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.
fonte
Aparentemente, sou a primeira pessoa da Obj-C / Cocoa a responder a essa pergunta.
Não vai ganhar nenhum jogo de código de golfe com isso.
fonte
[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.Eu acho que "Adicionar" ou "Mais" soa bem. O nome da lista em si deve ser suficiente para transmitir a imutabilidade da lista.
fonte
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
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
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,
add
não significa necessariamente que você muda alguma coisa. Certamente, entendo que ter uma declaração solitária contendo apenas umadd
e 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 :)fonte
Olhando http://thesaurus.reference.com/browse/add e http://thesaurus.reference.com/browse/plus , encontrei ganho e afixo, mas não sei ao certo quanto eles implicam em não-mutação.
fonte
Eu acho que
Plus()
eMinus()
ou, alternativamenteIncluding()
,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.
fonte
Append
- porque, observe que os nomes dosSystem.String
métodos sugerem que eles mudam a instância, mas não o fazem.Ou eu gosto bastante de
AfterAppending
:fonte
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 usadolist.copyWithout(null)
para remover elementos não configurados.fonte
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.
fonte