language-agnostic naming-conventions list immutability

language agnostic - ¿Cuál es el mejor nombre para un método de "adición" no mutante en una colección inmutable?



language-agnostic naming-conventions (30)

¿Qué hay de Chain () o Attach ()?

Lo siento por el título de 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 construir una lista de cadenas con valores "Hola", "inmutable", "mundo" se 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 de C # si cree que el idioma es importante. No es fundamentalmente una pregunta sobre el idioma, pero los modismos del idioma pueden ser importantes).

Lo importante es que Foo no modifica las listas existentes, por lo que está empty.Count aún devolverá 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?

EDIT 3 : como revelo más adelante, el nombre del tipo podría no ser ImmutableList<T> , lo que aclara la posición. Imagina, en cambio, que es TestSuite y que es inmutable porque todo el marco del que forma parte es inmutable ...

(Fin de la edición 3)

Opciones que he encontrado 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 los lenguajes funcionales, pero sin sentido para aquellos que no tienen experiencia en tales 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 : coherente con algunas otras convenciones inmutables, pero no tiene el mismo "agregado" que IMO.
  • And : no muy descriptivo.
  • Sobrecarga del operador para +: Realmente no me gusta mucho esto; Por lo general, creo que los operadores solo deben aplicarse a los tipos de niveles inferiores. 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

Por favor, pregunte por más detalles si no estoy siendo lo suficientemente claro ...

EDITAR 1: Aquí está mi razonamiento para preferir Plus a 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 es claramente defectuoso, es como escribir "x + 5;" como una declaración por sí misma. La primera línea parece estar 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 que Plus es mi favorito. Sin el ligero asco de la sobrecarga del operador, sigue teniendo las mismas connotaciones, que incluyen (para mí) no mutar los operandos (o el objetivo del método en este caso).

EDITAR 2: Razones para no gustar Añadir.

Varias respuestas son efectivas: "Vaya con Agregar. Eso es lo que DateTime hace, y String tiene métodos de Replace , etc. que no hacen que la inmutabilidad sea obvia". Estoy de acuerdo, hay precedencia aquí. Sin embargo, he visto a mucha gente llamar a DateTime.Add o String.Replace y esperar la mutación . Hay un montón de preguntas de grupos de noticias (y probablemente SO si busco) que se responden con "Estás ignorando el valor de retorno de String.Replace ; las cadenas son inmutables, se devuelve una nueva cadena".

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

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

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

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

Eso 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 la mendicidad de ser:

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

Idealmente, me gustaría que a mis usuarios no se les diga que el conjunto de pruebas es inmutable. Quiero que caigan en el hoyo del éxito. Esto puede no ser posible, pero me gustaría intentarlo.

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


Agregado (), Anexado ()

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

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


Algunos pensamientos al azar:

  • ImmutableAdd ()
  • Adjuntar()
  • ImmutableList <T> (ImmutableList <T> originalList, T newItem) Constructor

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 juntos 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 claro lo que va a contener cada variable. Debe quedar claro que list2 no se modifica en la última línea, sino que a esa list3 se le asigna el resultado de agregar "palabra" a list2 .

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


Creo que la clave a la que estás tratando de llegar 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 ().


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


En realidad me gusta And , sobre todo de 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");


En situaciones así, suelo ir con Concat . Eso usualmente me implica que se está creando un nuevo objeto.

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


Iría con Contras, por una sencilla razón: significa exactamente lo que usted quiere.

  1. Soy un gran fan 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 leerlo y usarlo mil 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 no tenga sentido para las personas sin experiencia en PF es realmente 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, en lugar de asumir incorrectamente que sabe lo que Add hace.

  3. Otras operaciones tomadas de lenguajes funcionales a menudo conservan sus nombres originales, sin catástrofes aparentes. No he visto ningún impulso para encontrar sinónimos para "mapear" y "reducir" que suenen más familiares para los usuarios que no tienen FP, ni tampoco veo ningún beneficio al hacerlo.

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


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

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


No creo que el idioma inglés le permita implicar la inmutabilidad de una manera inequívoca mientras usa un verbo que significa lo mismo que "Agregar". "Más" casi lo hace, pero la gente todavía puede cometer el error.

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

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


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


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

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

O bien, agregue "A lo largo" con él .. :)

object.AlongWith("this new item");


Primero, un punto de inicio 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 la 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. And tiene una connotación lógica adicional, pero ambas palabras se aplican intuitivamente a las listas. Add acción de connotes agregada se realiza en un objeto, lo que entra en conflicto con la semántica inmutable del método.

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

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


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


Siempre que estoy en un aprieto con la nomenclatura, golpeo las interwebs.

thesaurus.com devuelve esto para "agregar":

Definición: adjuntar, aumentar; hacer más comentario

Sinónimos: adjuntar, anexar, ante, adjuntar, aumentar, reforzar, aumentar, aumentar, cargar, continuar, indicar, completar, calentar, caminar, subir, enganchar, enganchar, enganchar con, incluir, elevar, jazz arriba, unirse, pad, parlay, piggyback, enchufar, verter, responder, correr, decir más, dar una palmada, bola de nieve, sopa arriba, acelerar, clavar, intensificar, suplemento, endulzar, pegar, etiqueta

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 a unirse a otras ImmutableList<> ''s.


Tal vez la confusión se deriva del 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!");

Copy devolvería un objeto intermedio, que es una copia mutable de la lista original. With volverí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 operación de Copy :

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

Ahora, la operación de Copy 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 o ordenar la lista. También se puede utilizar en el constructor ImmutableList 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 mala interpretación por parte de los usuarios, naturalmente caerán en el hoyo del éxito .

Otra actualización más:

Si aún 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 guión , 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 que Copy admita, no todas las capacidades de un IList .

Para el uso del 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 usa el mismo delegado en otro constructor:

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

Esto supone que el método rules.Append devuelve this .

Esto es lo que 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()) );


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 preocupa tanto que la gente confunda Add con un complemento mutante, ya que el nombre del tipo tiene el prefijo Immutable.

Por un tiempo consideré Contras y otros nombres de estilo funcionales. Eventualmente los desconté porque no son tan conocidos. Seguro que los programadores funcionales lo entenderán pero no son la mayoría de los usuarios.

Otros nombres: usted mencionó:

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

Opciones que consideré:

  • Concat: las cuerdas son inmutables y usan esto. Desafortunadamente solo es bueno para agregar al final.
  • CopyAdd: ¿Copiar qué? La fuente, la lista?
  • AddToNewList: Tal vez una buena para la lista. Pero ¿qué pasa con una colección, pila, cola, etc ...

Desafortunadamente, realmente 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 consideras colecciones distintas de la Lista. Tomemos por ejemplo la pila. 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 usen su colección.

Editar: Respuesta a Plus Editar

Veo a donde vas con Plus. Creo que un caso más fuerte sería en realidad menos para eliminar. Si viera lo siguiente sin duda me preguntaría qué pensaba el programador en el mundo

list.Minus(obj);

El mayor problema que tengo con Plus / Minus o una nueva pareja es que se siente como una exageración. La colección en sí ya tiene un nombre distintivo, el prefijo Inmutable. ¿Por qué ir más lejos agregando vocabulario cuya intención es agregar la misma distinción que el prefijo Inmutable ya hizo?

Puedo ver el argumento del sitio de llamadas. Lo hace más claro 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 atacar 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 debes saber que es inmutable a través de alguna otra fuente. Así que 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 qué es Inmutable y creo que eso también es válido. Ciertamente no lo supe hasta el año 2 en la universidad. Pero tienes el mismo problema con el nombre que elijas 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 la idea de que no deberías inventar nuevos nombres de métodos. Es decir, porque claramente hay un impulso para hacer que los tipos sean inmutables para 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 todos los tipos que use que sean inmutables.

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 tener que repensar todos los patrones de métodos de mutación que existen.

Ahora, ¿cómo puedes identificar TestSuite como Inmutable? En el entorno de hoy creo que hay algunas formas.

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

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


Yo lo llamaría Extender () o tal vez ExtendWith () si te apetece mucho.

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 los métodos de extensión: "agregan" un nuevo método a una clase sin "tocar" la clase en sí.

De lo contrario, si realmente quieres enfatizar que no modificas el objeto original, usa un prefijo como Get, me parece inevitable.


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


Join parece apropiado.


list.CopyWith(element)

Como hace Smalltalk :)

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


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.


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


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

Va a tirar a la Unión por ahí también. Prestado de SQL.


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


Creo que Plus()y Minus(), o, alternativamente Including(), Excluding()son razonables para implicar un comportamiento inmutable.

Sin embargo, ninguna opción de nomenclatura lo dejará perfectamente claro para todos, por lo que personalmente creo que un buen comentario de doc XML estará muy lejos. VS los lanza directamente a su cara cuando escribe el código en el IDE, son difíciles de ignorar.



Prefiero Plus (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 valor nuevo, igualmente inmutable.

Algunas otras posibilidades:

Empalme()

Injerto()

Unido()


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 sería bueno tener cierta simetría para esas palabras para otras acciones. No conozco una palabra similar para "Eliminar" que pienso del mismo tipo que "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 venir de mi fondo no inglés.

Tal vez yo usaría este esquema

AddToCopy RemoveFromCopy InsertIntoCopy

Estos tienen sus propios problemas, sin embargo, 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 juegan bien en el encadenamiento, creo. Demasiado wordy para escribir.

Tal vez solo usaría "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 cierta analogía. En mi opinión, addno significa necesariamente que mates algo. Ciertamente veo su punto de que tener una declaración solitaria que contenga solo un addobjeto nuevo y no usarlo no parece tener errores. Pero ahora también he pensado en la idea de usar otro nombre que no sea "agregar", pero simplemente no puedo encontrar otro nombre, sin hacerme pensar "hmm, tendría que consultar la documentación para saber qué se trata de "porque su nombre difiere de lo que yo esperaría que se llamara" agregar ". Solo un poco de extraño pensamiento sobre esto de Litb, no estoy seguro de que tenga sentido en absoluto :)