¿Cuál es el mejor nombre para un método "agregar" no mutante en una colección inmutable?

229

Perdón por el título waffly: si pudiera encontrar un título conciso, no tendría que hacer la pregunta.

Supongamos que tengo un tipo de lista inmutable. Tiene una operación Foo(x)que devuelve una nueva lista inmutable con el argumento especificado como un elemento adicional al final. Entonces, para crear una lista de cadenas con los valores "Hola", "inmutable", "mundo", podría escribir:

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

(Este es el código C #, y estoy más interesado en una sugerencia C # si considera que el idioma es importante. No es fundamentalmente una pregunta de idioma, pero los modismos del idioma pueden ser importantes).

Lo importante es que las listas existentes no se alteran, por Foolo empty.Countque aún devolvería 0.

Otra forma (más idiomática) de llegar al resultado final sería:

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

Mi pregunta es: ¿cuál es el mejor nombre para Foo?

EDITAR 3 : Como revelaré más adelante, el nombre del tipo podría no serlo ImmutableList<T>, lo que aclara la posición. Imagine en cambio que es TestSuitey que es inmutable porque todo el marco del que forma parte es inmutable ...

(Fin de la edición 3)

Opciones que se me han ocurrido hasta ahora:

  • Add: común en .NET, pero implica la mutación de la lista original
  • Cons: Creo que este es el nombre normal en lenguajes funcionales, pero no tiene sentido para aquellos sin experiencia en dichos lenguajes
  • Plus: mi favorito hasta ahora, no implica mutación para mí . Aparentemente, esto también se usa en Haskell, pero con expectativas ligeramente diferentes (un programador de Haskell podría esperar que agregue dos listas juntas en lugar de agregar un solo valor a la otra lista).
  • With: consistente con algunas otras convenciones inmutables, pero no tiene la misma "incorporación" a la OMI.
  • And: no muy descriptivo.
  • Sobrecarga del operador para +: Realmente no me gusta tanto; En general, creo que los operadores solo deberían aplicarse a los tipos de nivel inferior. ¡Aunque estoy dispuesto a ser persuadido!

Los criterios que estoy usando para elegir son:

  • Da la impresión correcta del resultado de la llamada al método (es decir, que es la lista original con un elemento adicional)
  • Deja lo más claro posible que no muta la lista existente
  • Suena razonable cuando se encadenan juntos como en el segundo ejemplo anterior

Solicite más detalles si no me estoy aclarando lo suficiente ...

EDIT 1: Aquí está mi razonamiento para preferir Plusa Add. Considere estas dos líneas de código:

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

Desde mi punto de vista (y esto es algo personal), este último tiene errores, es como escribir "x + 5"; como una declaración por sí sola. Parece que la primera línea está bien, hasta que recuerdes que es inmutable. De hecho, la forma en que el operador plus por sí solo no muta sus operandos es otra razón por la cual Pluses mi favorito. Sin la ligera aspereza de la sobrecarga del operador, todavía da las mismas connotaciones, que incluyen (para mí) no mutar los operandos (o el objetivo del método en este caso).

EDIT 2: Razones para no gustar Agregar.

Varias respuestas son efectivas: "Vaya con Agregar. Eso es lo que DateTimehace, y Stringtiene Replacemétodos, etc. que no hacen obvia la inmutabilidad". Estoy de acuerdo, hay prioridad aquí. Sin embargo, he visto un montón de personas que llaman DateTime.Addo String.Replacey esperan que la mutación . Hay un montón de preguntas de grupos de noticias (y probablemente SO si cavo) que son respondidas por "Estás ignorando el valor de retorno de String.Replace; las cadenas son inmutables, se devuelve una nueva cadena".

Ahora, debo revelar una sutileza a la pregunta: el tipo podría no ser realmente una lista inmutable, sino un tipo inmutable diferente. En particular, estoy trabajando en un marco de evaluación comparativa en el que agrega pruebas a una suite, y eso crea una nueva suite. Puede ser obvio que:

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

no va a lograr nada, pero se vuelve mucho más oscuro cuando lo cambia a:

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

Parece que debería estar bien. Mientras que esto, para mí, aclara el error:

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

Eso es solo rogar ser:

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

Idealmente, me gustaría que mis usuarios no tengan que decirles que el conjunto de pruebas es inmutable. Quiero que caigan en el pozo del éxito. Puede que esto no sea posible, pero me gustaría intentarlo.

Pido disculpas por simplificar demasiado la pregunta original al hablar solo de un tipo de lista inmutable. No todas las colecciones son tan autodescriptivas como ImmutableList<T>:)

Jon Skeet
fuente
2
@ Adam: No, este último tiene errores. En realidad, ambos tienen errores (ya que no están haciendo nada con el resultado), pero el primero no me parece defectuoso.
Jon Skeet
36
¿Un uncat es un perro?
Michael Myers
77
Concat / Condog ... ¡funciona para mí! ;)
gnovice
11
Uncat: ese sería un gato zombie.
Erik Forbes
2
@Trap: Eso apesta en términos de hacer que la API sea fluida.
Jon Skeet

Respuestas:

130

En situaciones como esa, suelo ir con ellos Concat. Eso generalmente me implica que se está creando un nuevo objeto.

var p = listA.Concat(listB);
var k = listA.Concat(item);
MojoFilter
fuente
3
Esto es lo que uso, porque es lo que usa System.Linq.Enumerable: la decisión ya está tomada. :) No puedo ser la única persona que ha definido su propia sobrecarga de la extensión Concat en IEnumerable para aceptar un valor único que se agregará.
Daniel Earwicker
99
+1 Esta es la respuesta correcta para mantener la coherencia de nombres dentro del marco.
Sam Harwell
A menos que me falte, System.Linq.Enumerable (y Linq en general) solo usa Concat () para "secuencia + secuencia", nunca "elemento + secuencia". El problema de que alguien "podría esperar que agregue dos listas juntas en lugar de agregar un solo valor a la otra lista" se dio explícitamente como una razón para no usar una de las otras opciones originales.
Ssswift
119

Yo iría con Contras, por una simple razón: significa exactamente lo que quieres.

  1. Soy un gran fanático de decir exactamente lo que quiero decir, especialmente en el código fuente. Un novato tendrá que buscar la definición de Contras solo una vez, pero luego leerla y usarla miles de veces. Creo que, a largo plazo, es mejor trabajar con sistemas que facilitan el caso común, incluso si el costo inicial es un poco más alto.

  2. El hecho de que sería "sin sentido" para las personas sin experiencia en FP es en realidad una gran ventaja. Como señaló, todas las otras palabras que encontró ya tienen algún significado, y ese significado es ligeramente diferente o ambiguo. Un nuevo concepto debe tener una nueva palabra (o en este caso, una antigua). Prefiero que alguien tenga que buscar la definición de Contras, que suponer incorrectamente que sabe lo que hace Add.

  3. Otras operaciones prestadas de lenguajes funcionales a menudo mantienen sus nombres originales, sin catástrofes aparentes. No he visto ningún impulso para encontrar sinónimos de "mapa" y "reducir" que suenen más familiares para los que no son FPers, ni veo ningún beneficio al hacerlo.

(Divulgación completa: soy un programador Lisp, así que ya sé lo que significa Contras).

Conocido
fuente
16
Sin embargo, no olvide que la capacidad de detección es importante si escribo "testSuite". y mire la lista de métodos, me gustaría ver un método que sugiera lo correcto. Probablemente no buscaré un nombre sin sentido (para mí) por casualidad, es lo que quiero.
Jon Skeet
33
Si me sentía sarcástico, haría un método Add que simplemente arrojara una excepción con message = "Use Cons para anteponer a una ImmutableList". :-)
Ken
2
No matará a nadie leer algunas líneas de comentarios explicando por qué el nombre es lo que es, y refiriéndose a ellos, por ejemplo, "Estructura e interpretación de programas de computadora" de Abelson & Sussman.
John R. Strohm
16
Tradicionalmente, los contras se agregan al principio y no al final. Por lo tanto, es un nombre potencialmente engañoso para el método descrito.
walkytalky
16
Solo para guardar el siguiente programador no funcional un clic o 3 ... es.wikipedia.org/wiki/Cons de la palabra "construir", la expresión "cons contra x en y" significa construir un nuevo objeto con ( contras xy)
Myster
59

En realidad me gusta And, especialmente en la forma idiomática. Me gustaría especialmente si tuviera una propiedad de solo lectura estática para la lista vacía, y tal vez haga que el constructor sea privado para que siempre tenga que construir desde la lista vacía.

var list = ImmutableList<string>.Empty.And("Hello")
                                      .And("Immutable")
                                      .And("Word");
tvanfosson
fuente
Me gusta la idea vacía. Todavía no estoy convencido de Y aunque. Es solo un poco bla.
Jon Skeet
Parece más bien cómo pensaría en construir una lista de cosas en lenguaje natural. Si lo lee en voz alta, parece más intuitivo que Agregar o Más. "lista" es la lista vacía y "Hola" e "Inmutable" y "Word". Sin embargo, estaría de acuerdo en que es menos claro de forma aislada.
tvanfosson
52

Cada vez que estoy en un atasco con la nomenclatura, golpeo las interwebs.

thesaurus.com devuelve esto para "agregar":

Definición: contiguo, aumento; hacer más comentarios

Sinónimos: anexar, anexar, ante, agregar, aumentar, aumentar, aumentar, aumentar, cargar, continuar, indicar, figura, desarrollar, calentar, caminar, caminar, enganchar, enganchar, enganchar con, incluir, gato, jazz, unirse, almohadilla, parlay, piggyback, enchufar, verter, responder, correr, decir más, abofetear, bola de nieve, sopa, acelerar, acelerar, intensificar, Suplemento, endulzar, pegar, etiquetar

Me gusta el sonido de Adjoin, o más simplemente Join. Eso es lo que estás haciendo, ¿verdad? El método también podría aplicarse para unirse a otros ImmutableList<>.

Spoulson
fuente
1
También me gusta "Unir", pero, en la mayoría de los casos, cuando unes 2 objetos, terminas con 1. En este caso, si unes 2 objetos, en realidad estás creando un nuevo objeto.
Outlaw Programmer
1
No conozco ningún caso en .NET, Perl, PHP o incluso VBScript donde Join implica mutación. El diseño es tal que A y B se unen para formar C, donde C siempre es una entidad nueva.
spoulson
Me gusta Join, y estoy totalmente de acuerdo con thesaurus.com :) Úselo todo el tiempo cuando tenga dudas sobre un nombre.
Skurmedel
var suite = nuevo TestSuite <string, int> () .Join (x => x.Length);
Sly Gryphon
3
Ve con Piggyback, imo. O conectar con.
Chris Marasti-Georg
48

Personalmente, me gusta .With (). Si estaba usando el objeto, después de leer la documentación o los comentarios del código, sería claro lo que hace, y se lee bien en el código fuente.

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

O bien, agregue "Along" con él .. :)

object.AlongWith("this new item");
LarryF
fuente
+1. "WITH" es un operador infijo en SETL que hace lo mismo. Si SETL lo usa, entonces debe ser correcto :-)
finnw
1
Bah ... ¿Quién usa VB más? :) Uh ... Opps ... ¿Fue eso en voz alta? je .. Pero, no, con toda seriedad, es por eso que consideré el "AlongWith", eso eliminaría el problema de VB. Hay solo alrededor de un millón de formas diferentes en que podría ir con esta ... quiero decir, incluso las más locas como: object.Plus () u Object.ExistingPlus () ... etc ... Es una muy buena pregunta que él publicado, sin embargo ...
jeh
33

Terminé yendo con Agregar para todas mis colecciones inmutables en BclExtras . La razón es que es un nombre fácil de predecir. No me preocupan tanto las personas que confunden Add con un add mutante, ya que el nombre del tipo tiene el prefijo Immutable.

Por un tiempo consideré Cons y otros nombres de estilo funcional. Finalmente los descarté porque no son tan conocidos. Claro que los programadores funcionales lo entenderán, pero no son la mayoría de los usuarios.

Otros nombres: usted mencionó:

  • Además: estoy deseoso / lavado en este caso. Para mí, esto no lo distingue como una operación no mutante más que Add hace
  • Con: causará problemas con VB (juego de palabras)
  • Sobrecarga del operador: la capacidad de detección sería un problema

Opciones que consideré:

  • Concat: las cadenas son inmutables y usan esto. Desafortunadamente, solo es realmente bueno para agregar al final
  • CopyAdd: ¿Copiar qué? La fuente, la lista?
  • AddToNewList: Quizás sea bueno para List. Pero, ¿qué pasa con una colección, pila, cola, etc.?

Lamentablemente, en realidad no parece haber una palabra que sea

  1. Definitivamente una operación inmutable.
  2. Comprensible para la mayoría de los usuarios.
  3. Representable en menos de 4 palabras.

Se vuelve aún más extraño cuando considera colecciones distintas a la Lista. Tomemos por ejemplo Stack. Incluso los programadores de primer año pueden decirle que las pilas tienen un par de métodos Push / Pop. Si crea un ImmutableStack y le da un nombre completamente diferente, llamémoslo Foo / Fop, acaba de agregar más trabajo para que puedan usar su colección.

Editar: Respuesta a Plus Editar

Veo a dónde vas con Plus. Creo que un caso más fuerte sería en realidad menos para eliminar. Si veía lo siguiente, sin duda me preguntaría qué demonios estaba pensando el programador.

list.Minus(obj);

El mayor problema que tengo con Plus / Minus o un nuevo emparejamiento es que parece excesivo. La colección en sí ya tiene un nombre distintivo, el prefijo Inmutable. ¿Por qué ir más allá agregando vocabulario cuya intención es agregar la misma distinción que el prefijo Inmutable?

Puedo ver el argumento del sitio de la llamada. Lo aclara desde el punto de vista de una sola expresión. Pero en el contexto de toda la función parece innecesario.

Editar 2

De acuerdo en que la gente definitivamente ha sido confundida por String.Concat y DateTime.Add. He visto a varios programadores muy brillantes resolver este problema.

Sin embargo, creo que ImmutableList es un argumento diferente. No hay nada sobre String o DateTime que lo establezca como Inmutable para un programador. Simplemente debe saber que es inmutable a través de alguna otra fuente. Entonces la confusión no es inesperada.

ImmutableList no tiene ese problema porque el nombre define su comportamiento. Se podría argumentar que la gente no sabe lo que es Inmutable y creo que eso también es válido. Ciertamente no lo supe hasta aproximadamente el año 2 en la universidad. Pero tiene el mismo problema con el nombre que elija en lugar de Agregar.

Edición 3: ¿Qué pasa con los tipos como TestSuite que son inmutables pero no contienen la palabra?

Creo que esto lleva a casa la idea de que no deberías estar inventando nuevos nombres de métodos. Principalmente porque claramente existe un impulso para hacer que los tipos sean inmutables a fin de facilitar las operaciones paralelas. Si se enfoca en cambiar el nombre de los métodos para las colecciones, el siguiente paso serán los nombres de los métodos de mutación en cada tipo que use que sea inmutable.

Creo que sería un esfuerzo más valioso centrarse en hacer que los tipos sean identificables como inmutables. De esa manera, puede resolver el problema sin repensar cada patrón de método de mutación.

Ahora, ¿cómo puede identificar TestSuite como inmutable? En el entorno actual, creo que hay algunas maneras

  1. Prefijo con Inmutable: ImmutableTestSuite
  2. Agregue un atributo que describa el nivel de Immutablitiy. Esto es ciertamente menos reconocible
  3. No mucho mas.

Mi conjetura / esperanza es que las herramientas de desarrollo comenzarán a ayudar a este problema al facilitar la identificación de tipos inmutables simplemente a simple vista (color diferente, fuente más fuerte, etc.). Pero creo que esa es la respuesta sobre cambiar todos los nombres de métodos.

JaredPar
fuente
He agregado razones para mi preferencia por Plus sobre Agregar a la pregunta. Agradecería comentarios sobre ese razonamiento. Estoy realmente abierto a la idea de que estoy siendo tonto.
Jon Skeet
@JaredPar: ¿Y si el tipo se llama TestSuite?
Jon Skeet
Me encantaría dar otro +1 para la edición 3, pero obviamente no puedo. (En mi caso, no estoy tratando de obtener paralelismo; creo que la inmutabilidad conduce a un código que es más fácil de razonar). Todavía no estoy del todo convencido de que Add sea el camino a seguir, pero el soporte en las respuestas aquí Es persuasivo.
Jon Skeet
Si pudieras dejar caer esta pregunta en una conversación en el trabajo, eso también sería increíble, por cierto. Comencé la discusión en una lista de C #, por lo que algunos colegas ya pueden estar involucrados. Podría preguntar internamente en Google también ...
Jon Skeet
@ Jon, creo que conozco un buen lugar para dejar esta pregunta en el trabajo :)
JaredPar
27

Creo que esta puede ser una de esas situaciones raras en las que es aceptable sobrecargar al +operador. En terminología matemática, sabemos que +no agrega algo al final de otra cosa. Siempre combina dos valores y devuelve un nuevo valor resultante.

Por ejemplo, es intuitivamente obvio que cuando dices

x = 2 + 2;

El valor resultante de x es 4, no 22.

Similar,

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

debería dejar en claro qué va a contener cada variable. Debe quedar claro que list2no se cambia en la última línea, sino que list3se le asigna el resultado de agregar "palabra" a list2.

De lo contrario, simplemente nombraría la función Plus ().

Bill el lagarto
fuente
¿Qué sucede si tiene una lista genérica, a la que legítimamente podría agregar un entero (digamos) u otra lista de enteros? Entonces este uso de + entrará en conflicto con la concatenación.
finnw
@finnw: No entiendo tu punto. Con una lista siempre esperaría que + signifique agregar, ya sea que esté agregando un elemento o muchos.
Bill the Lizard
44
Para una API reutilizable, es una buena idea tener también un método con nombre, en caso de que alguien esté usando su clase desde un idioma sin sobrecarga del operador.
Neil
"si está agregando un elemento o muchos", ¿qué sucede si desea agregar la lista como un elemento único? es decir, [1] + 2 = [1,2]pero [1] + [2] = [1,[2]]. Lo que estás sugiriendo es un comportamiento inconsistente. Esta es probablemente la razón por la cual Python no le permite agregar un elemento de esta manera.
mpen
Bueno, en un lenguaje de tipo estático como C #, puede saber cuál es el tipo de elementos de la lista, ya sea una lista de listas o una lista de elementos, por lo que puede usar el tipo para decidir si agregar un elemento que es una lista o concatenar Las dos listas.
Dobes Vandermeer
22

Para ser lo más claro posible, es posible que desee ir con la palabra CopyAndAdd, o algo similar.

Michael Myers
fuente
Sin embargo, no todas las colecciones inmutables requieren una copia para agregar. Piense en árboles inmutables, solo necesitan un nuevo nodo y pueden usar el árbol existente como una hoja.
JaredPar
Por cierto, leí tu perfil, luego envejecí en orden y me sorprendió brevemente la edad que tenías. La cordura pateó poco después.
JaredPar
Re primer comentario: uso árboles tan raramente que ese pensamiento nunca se me ocurrió. Ese es un buen punto.
Michael Myers
Re segundo comentario: lo confieso, ¡lo hice por la insignia! Simplemente no me gusta revelar mi edad. (De hecho, soy más joven que tú, pero puedo jugar al viejo veterano bastante bien si lo necesito. Y no soy el único cuya edad figura en 89.)
Michael Myers
El argumento de los árboles inmutables es fuerte, buen punto. Entonces EquivalentReferenceWithAdded (x) lucharía contra ese argumento, pero suena estúpido y difícil de deducir.
TheBlastOne
21

Lo llamaría Extend () o tal vez ExtendWith () si te sientes realmente detallado.

Extender significa agregar algo a otra cosa sin cambiarlo. Creo que esta es una terminología muy relevante en C # ya que es similar al concepto de métodos de extensión: "agregan" un nuevo método a una clase sin "tocar" la clase en sí.

De lo contrario, si realmente desea enfatizar que no modifica el objeto original en absoluto, usar algún prefijo como Get- me parece inevitable.

revs DrJokepu
fuente
1
Aún así, implica hacer algo al objeto base.
caos
18

Agregado (), Agregado ()

Me gusta usar el tiempo pasado para operaciones en objetos inmutables. Transmite la idea de que no está cambiando el objeto original, y es fácil de reconocer cuando lo ve.

Además, debido a que los nombres de métodos de mutación a menudo son verbos en tiempo presente, se aplica a la mayoría de los casos necesarios de nombre de método inmutable con los que se encuentra. Por ejemplo, una pila inmutable tiene los métodos "empujado" y "reventado".

Strilanc
fuente
1
Python también usa esta convención. Por ejemplo, las funciones integradas invertida () y ordenada ().
Joe
18

Me gusta la sugerencia de mmyers de CopyAndAdd . De acuerdo con un tema de "mutación", ¿tal vez podrías elegir Bud (reproducción asexual), Grow , Replicate o Evolve ? =)

EDITAR: Para continuar con mi tema genético, ¿qué tal Procreate , lo que implica que se crea un nuevo objeto que se basa en el anterior, pero con algo nuevo agregado.

gnovice
fuente
14

Probablemente sea una exageración, pero en Ruby hay una notación de uso común para la distinción: addno muta; add!mutantes Si este es un problema generalizado en su proyecto, también podría hacerlo (no necesariamente con caracteres no alfabéticos, sino que utiliza una notación para indicar métodos mutantes / no mutantes).

ykaganovich
fuente
+1. esto no es impuesto por el lenguaje, sino acordado como una convención. Me gusta eso.
oma
13

Join Parece apropiado

ykaganovich
fuente
13

Tal vez la confusión se deba al hecho de que desea dos operaciones en una. ¿Por qué no separarlos? Estilo DSL:

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

Copydevolvería un objeto intermedio, que es una copia mutable de la lista original. Withdevolvería una nueva lista inmutable.

Actualizar:

Pero, tener una colección intermedia y mutable no es un buen enfoque. El objeto intermedio debe estar contenido en la Copyoperación:

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

Ahora, la Copyoperación toma un delegado, que recibe una lista mutable, para que pueda controlar el resultado de la copia. Puede hacer mucho más que agregar un elemento, como eliminar elementos u ordenar la lista. También se puede usar en el ImmutableListconstructor para ensamblar la lista inicial sin listas inmutables intermedias.

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

Ahora no hay posibilidad de que los usuarios malinterpreten, naturalmente caerán en el pozo del éxito .

Otra actualización más:

Si todavía no le gusta la mención de la lista mutable, incluso ahora que está contenida, puede diseñar un objeto de especificación, que especificará , o script , cómo la operación de copia transformará su lista. El uso será el mismo:

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

Ahora puede ser creativo con los nombres de las reglas y solo puede exponer la funcionalidad que desea Copyadmitir, no todas las capacidades de un IList.

Para el uso de encadenamiento, puede crear un constructor razonable (que no utilizará el encadenamiento, por supuesto):

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

...

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

O use el mismo delegado en otro constructor:

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

Esto supone que el rules.Appendmétodo vuelve this.

Así es como se vería con su último ejemplo:

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
fuente
@ Jordan: porque este tipo de composición conduce a una forma de inicialización mucho más simple ¿Por qué tener dos variables separadas cuando solo quiero una? Del mismo modo, no quiero crear una copia mutable; quiero que todo sea inmutable, ya que eso conduce a un código que es más fácil de razonar, IMO.
Jon Skeet
Todos estos son aún más difíciles de manejar que "Plus", etc. Gracias por las ideas que involucran la mutación, pero definitivamente prefiero el enfoque de "mantenerlo inmutable".
Jon Skeet
Quizás entonces siempre habrá interpretaciones erróneas sobre cuáles son las semánticas reales de la operación. Si sigue la ruta del objeto de especificación, no está ocurriendo una mutación (al menos no externamente), el objeto solo especifica cómo se verá el nuevo objeto inmutable. Lo que tienes es una operación que va de un objeto inmutable a otro, y como se llama Copiar, no hay lugar para malentendidos.
Jordão
Los únicos nombres que funcionarían para usted parecen ser nombres compuestos, como CopyAndAppend, CopyAndAdd, etc.
Jordão
1
De hecho, estoy cada vez más interesado en este enfoque (con todas las ediciones) como API para colecciones inmutables. Sin embargo, diría que combinar este enfoque con métodos auxiliares para especificaciones predeterminadas, como Concat, ofrece lo mejor de ambos mundos.
cáñamo
11

Algunos pensamientos al azar:

  • ImmutableAdd ()
  • Adjuntar()
  • Constructor ImmutableList <T> (ImmutableList <T> originalList, T newItem)
Chris Shaffer
fuente
1
+1 para ImmutableAdd; no está interesado en Append (demasiado parecido a StringBuilder.Append que está mutando) y la versión del constructor es una molestia en términos de encadenamiento.
Jon Skeet
10

DateTime en C # utiliza Agregar. Entonces, ¿por qué no usar el mismo nombre? Mientras los usuarios de su clase entiendan que la clase es inmutable.

Tundey
fuente
Yo diría que se sabe que DateTime.Add confunde a las personas ... pero estoy de acuerdo en que muestra prioridad.
Jon Skeet
1
Al igual que los métodos para mutar una cadena son confusos para los nuevos desarrolladores. Pero pronto todos aprenden que "las cuerdas son inmutables"
Tundey
9

Creo que la clave a la que estás tratando de llegar y que es difícil de expresar es la no permutación, así que tal vez algo con una palabra generativa, algo como CopyWith () o InstancePlus ().

caos
fuente
9

No creo que el idioma inglés le permita implicar la inmutabilidad de una manera inconfundible mientras usa un verbo que significa lo mismo que "Agregar". "Plus" casi lo hace, pero la gente aún puede cometer el error.

La única forma de evitar que los usuarios confundan el objeto con algo mutable es haciéndolo explícito, ya sea a través del nombre del objeto en sí o mediante el nombre del método (como con las opciones detalladas como "GetCopyWith" o "CopyAndAdd").

Así que ve con tu favorito, "Plus".

Adam Bellaire
fuente
9

Primero, un punto de partida interesante: http://en.wikipedia.org/wiki/Naming_conventions_(programming) ... En particular, verifique los enlaces "Ver también" en la parte inferior.

Estoy a favor de Plus o And, efectivamente por igual.

Plus y And están basados ​​en matemáticas en etimología. Como tal, ambos connotan operación matemática; ambos producen una expresión que se lee naturalmente como expresiones que pueden resolverse en un valor, que se ajusta al método que tiene un valor de retorno. Andlleva una connotación lógica adicional, pero ambas palabras se aplican intuitivamente a las listas. Addconnota la acción realizada en un objeto, que entra en conflicto con la semántica inmutable del método.

Ambos son cortos, lo cual es especialmente importante dada la primitividad de la operación. Las operaciones simples y realizadas con frecuencia merecen nombres más cortos.

Expresar la semántica inmutable es algo que prefiero hacer a través del contexto. Es decir, prefiero simplemente implicar que todo este bloque de código tiene una sensación funcional; Supongamos que todo es inmutable. Eso podría ser solo yo, sin embargo. Prefiero la inmutabilidad como regla; si se hace, se hace mucho en el mismo lugar; La mutabilidad es la excepción.

Paul Brinkley
fuente
8

¿Qué tal Chain () o Attach ()?

Webjedi
fuente
1
Adjuntar seguramente suena como estar mutando. Quizás WithAttached sería más sabio, pero está muy cerca de WithAdded, que se ha discutido anteriormente.
TheBlastOne
Es curioso cuántas veces se menciona el "encadenamiento" al describir lo que se intenta hacer con esto. (5 veces), pero no se ofrece como sugerencia! Es lo primero que surgió visualthesaurus.com(sin afiliación) cuando busqué concatenate.
cod3monk3y
7

Prefiero más (y menos). Son fácilmente comprensibles y se asignan directamente a operaciones que involucran tipos inmutables bien conocidos (los números). 2 + 2 no cambia el valor de 2, devuelve un nuevo valor, igualmente inmutable.

Algunas otras posibilidades:

Empalme()

Injerto()

Juntar a()

2 revoluciones
fuente
6

¿Qué hay de mate , mateWith o coito , para aquellos que acatan? En términos de reproducción, los mamíferos generalmente se consideran inmutables.

Voy a echar a Union por ahí también. Prestado de SQL.

jason saldo
fuente
2
+1 para Union. Sin embargo, lo tomo prestado directamente de la teoría de conjuntos. :-)
Christoffer Lette
¿SQL no obtiene gran parte de su terminología de la teoría de conjuntos?
Jason D
1
Además, Union implica distinción. Si desea incluir duplicados (al menos en TSQL), debe usar Union All explícitamente.
cáñamo
6

Aparentemente soy la primera persona de Obj-C / Cocoa en responder esta pregunta.

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

No voy a ganar ningún código de juegos de golf con esto.

kubi
fuente
+1 el [object]By[Verb]ing[Object]:prefijo al método implica que se devolverá una nueva cadena en lugar de simplemente [verb][Object]:, lo que mutaría el objeto en su lugar.
Dave DeLong
3
+1. No entiendo la aversión de la gente a la verbosidad (también conocida como autodocumentación).
hatfinch
5

Creo que "Agregar" o "Más" suena bien. El nombre de la lista en sí debería ser suficiente para transmitir la inmutabilidad de la lista.

David Morton
fuente
No es una lista, es un conjunto de pruebas.
tstenner
5

Tal vez hay algunas palabras que me recuerdan más de hacer una copia y agregar cosas a eso en lugar de mutar la instancia (como "Concatenar"). Pero creo que tener algo de simetría para esas palabras para otras acciones también sería bueno. No sé de una palabra similar para "Eliminar" que pienso del mismo tipo como "Concatenar". "Plus" me suena un poco extraño. No esperaría que se usara en un contexto no numérico. Pero eso también podría provenir de mi origen no inglés.

Tal vez usaría este esquema

AddToCopy
RemoveFromCopy
InsertIntoCopy

Sin embargo, estos tienen sus propios problemas, cuando lo pienso. Uno podría pensar que eliminan algo o agregan algo a un argumento dado. No estoy seguro de eso en absoluto. Esas palabras tampoco son buenas para encadenar, creo. Demasiado prolijo para escribir.

Tal vez usaría simplemente "Agregar" y amigos también. Me gusta como se usa en matematicas

Add 1 to 2 and you get 3

Bueno, ciertamente, un 2 sigue siendo un 2 y obtienes un nuevo número. Se trata de dos números y no de una lista y un elemento, pero creo que tiene alguna analogía. En mi opinión, addno necesariamente significa que mutas algo. Ciertamente veo su punto de vista de que tener una declaración solitaria que contenga solo un addy no use el nuevo objeto devuelto no parece tener errores. Pero ahora también he pensado alguna vez en la idea de usar otro nombre que no sea "agregar", pero no puedo encontrar otro nombre, sin hacerme pensar "hmm, tendría que mirar la documentación para saber qué se trata de "porque su nombre difiere de lo que esperaría que se llamara" agregar ". Solo un pensamiento extraño sobre esto de litb, no estoy seguro de que tenga sentido en absoluto :)

revs Johannes Schaub - litb
fuente
Pero una copia no siempre es necesaria en una colección inmutable. Tome un árbol binario, por ejemplo. Agregar una nueva raíz no requiere copia, solo un nuevo valor donde una de las hojas es el árbol viejo
JaredPar
BESO: si la nomenclatura comenzara a incluir detalles de implementación, todos los nombres de métodos serían demasiado largos. "agregar" es bastante simple y hace el trabajo.
mP.
1
@mP: Nuevamente usas la frase "detalle de implementación" de una manera que creo que no es adecuada. Si se trata de una lista vinculada o una matriz debajo del capó es un detalle de implementación . Podría cambiar la implementación sin cambiar la API. El aspecto inmutable no es un detalle de implementación.
Jon Skeet
1
Derecha. JaredPar, pero creo que tampoco es importante si realmente copia el árbol o simplemente usa el árbol existente y lo usa como una hoja para el nuevo árbol devuelto. Quiero decir, eso es solo un detalle de implementación. es lo mismo para (creo) la operación de subcadena para la clase de cadena de java.
Johannes Schaub - litb
5

Creo que Plus()y Minus()o, alternativamente, Including(), Excluding()son razonables en lo que implica el comportamiento inmutable.

Sin embargo, ninguna elección de nombres lo dejará perfectamente claro para todos, por lo que personalmente creo que un buen comentario de documento xml sería muy útil aquí. VS arroja esto directamente a su cara cuando escribe código en el IDE; son difíciles de ignorar.

LBushkin
fuente
4

Append- porque, tenga en cuenta que los nombres de los System.Stringmétodos sugieren que mutan la instancia, pero no lo hacen.

O me gusta bastante AfterAppending:

void test()
{
  Bar bar = new Bar();
  List list = bar.AfterAppending("foo");
}
ChrisW
fuente
Al igual que el argumento anterior DateTime, estaría de acuerdo con la preferencia si no fuera por el hecho de que muchos programadores no esperan métodos de string para hacer cosas. Hay que decirles (a veces repetidamente) que las cadenas son inmutables. Me gustaría atraer a mis desarrolladores de clientes al pozo del éxito :)
Jon Skeet
Me gusta agregar más y más. Distingue que no estás mutando la colección sino uniéndote a ella.
4

list.CopyWith(element)

Al igual que Smalltalk :)

Y también list.copyWithout(element)eso elimina todas las apariciones de un elemento, lo cual es más útil cuando se usa list.copyWithout(null)para eliminar elementos no definidos.

akuhn
fuente
3

Iría por Agregar, porque puedo ver el beneficio de un mejor nombre, pero el problema sería encontrar nombres diferentes para cada otra operación inmutable que podría hacer que la clase no sea familiar si eso tiene sentido.

Joan Venge
fuente
Sí, entiendo tu punto. Creo que todavía prefiero Plus, pero es un punto que vale la pena considerar.
Jon Skeet el
Gracias Jon Tengo muchas ganas de utilizar su marco. Acabo de leer sobre eso y se ve muy bien. Gracias de nuevo.
Joan Venge