Яке найкраще ім’я для немутуючого методу "додати" для незмінної колекції?


229

Вибачте за вафельний заголовок - якби я міг придумати стислий заголовок, мені не доведеться ставити питання.

Припустимо, у мене є незмінний тип списку. Він має операцію, Foo(x)яка повертає новий незмінний список із вказаним аргументом як додатковий елемент в кінці. Отже, для складання списку рядків зі значеннями "Привіт", "незмінний", "світ" ви можете написати:

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

(Це код C #, і мене найбільше цікавить пропозиція C #, якщо ви вважаєте, що мова важлива. Це не принципово мовне питання, але ідіоми мови можуть бути важливими.)

Важливим є те, що існуючі списки не змінені Foo- так empty.Countби все одно повернути 0.

Ще одним (більш ідіоматичним) способом досягнення кінцевого результату буде:

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

Моє запитання: яке найкраще ім’я для Фоо?

EDIT 3 : Як я виявив пізніше, назва типу може насправді не бути ImmutableList<T>, що робить позицію зрозумілою. Уявіть собі, натомість, що це TestSuiteі що це незмінне, оскільки вся структура, до якої вона входить, незмінна ...

(Кінець редагування 3)

Варіанти, які я придумав поки що:

  • Add: поширений у .NET, але передбачає мутацію вихідного списку
  • Cons: Я вважаю, що це нормальна назва у функціональних мовах, але безглуздо для тих, хто не має досвіду таких мов
  • Plus: мій улюблений поки що, це не означає для мене мутації . Мабуть, це також використовується в Haskell, але з дещо іншими очікуваннями (програміст Haskell може очікувати, що він додасть два списки разом, а не додавати одне значення до іншого списку).
  • With: відповідає деяким іншим незмінним умовам, але не має такої ж «доповнення» до ІМО.
  • And: не дуже описовий.
  • Перевантаження оператора для +: мені це дуже не подобається; Як правило, я думаю, що операторів слід застосовувати лише до типів нижчого рівня. Я готовий переконати, хоча!

Критерії, які я використовую для вибору:

  • Створює правильне враження про результат виклику методу (тобто, це вихідний список із додатковим елементом)
  • Зробити це максимально зрозумілим, що він не мутує існуючий список
  • Звучить розумно, коли це пов'язано разом, як у другому прикладі вище

Будь ласка, запитайте детальніше, якщо я не даю про себе зрозуміти ...

EDIT 1: Ось мої міркування для вважаючи за краще , Plusщоб Add. Розглянемо ці два рядки коду:

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

На мій погляд (і це є особиста річ) останній явно глючить - це як лист «х + 5;» як твердження самостійно. Перший рядок виглядає, що це нормально, поки ви не згадаєте, що це непорушно. Насправді, те, що оператор plus самостійно не мутує своїх операндів, є ще однією причиною, чому Plusя мій улюблений. Без невеликої примхливості перевантаження оператора, він все ще надає ті самі конотації, які включають (для мене) не мутацію операндів (або мета методу в цьому випадку).

EDIT 2: Причини не подобається Додати.

Ефективні різні відповіді: "Ідіть з Add. Ось що і DateTimeробить, і Stringє Replaceметоди тощо, які не роблять незмінність очевидною". Я згоден - тут є пріоритет. Тим НЕ менше, я бачив багато людей називають DateTime.Addабо String.Replaceй очікувати мутації . Є безліч питань групи новин (і, мабуть, ТАК, якщо я викопаю), на які відповідає "Ви ігноруєте значення повернення String.Replace; рядки незмінні, повертається нова рядок".

Тепер я повинен розкрити тонкощі питання - тип може насправді не бути незмінним списком, а іншим незмінним типом. Зокрема, я працюю над базовою схемою, де ви додаєте тести до набору, і це створює новий набір. Можливо, очевидно, що:

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

не збирається нічого домогтися, але стає набагато муткішим, коли зміниш його на:

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

Це виглядає так, що має бути гаразд. Враховуючи це, для мене, помилка стає яснішою:

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

Це просто прохання бути:

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

В ідеалі я хотів би, щоб моїм користувачам не було сказано, що тестовий набір незмінний. Я хочу, щоб вони потрапили в яму успіху. Це може бути неможливо, але я б хотів спробувати.

Прошу вибачення за занадто спрощене початкове запитання, говорячи лише про незмінний тип списку. Не всі колекції є такими ж самоописовими, як ImmutableList<T>:)


2
@Adam: Ні, останній явно баггі. Вони обидва на самому ділі баггі ( так як вони не роблять нічого з результатом) - але перший НЕ виглядати баггі для мене.
Джон Скіт

36
Хіба що некута собака?
Майкл Майерс

7
Concat / Condog ... працює для мене! ;)
gnovice

11
Uncat - це була б зомбі-кішка.
Ерік Форбс

2
@ Trap: Хоча це і є з точки зору створення API рідини.
Джон Скіт

Відповіді:


130

У таких ситуаціях, як правило, я йду з цим Concat. Зазвичай для мене означає, що створюється новий об’єкт.

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

3
Це те, що я використовую, тому що це те, що використовує System.Linq. Безліч - рішення вже прийняте. :) Я не можу бути єдиною людиною, яка визначила власну перевантаження розширення Concat на IEnumerable, яка прийняла єдине значення, яке слід додати.
Даніель Ервікер

9
+1 Це правильна відповідь для підтримки узгодженості імен в рамках.
Сем Харвелл

Якщо я цього не пропускаю, System.Linq.Enumerable (і взагалі Linq) використовує лише Concat () для "послідовності + послідовності", ніколи "пункт + послідовність". Проблема того, що хтось "може очікувати, що він додасть два списки разом, а не додає одне значення до іншого списку", явно наводився як причина не використовувати одну з інших оригінальних опцій.
Ssswift

119

Я б пішов із мінусами з однієї простої причини: це означає саме те, що ти хочеш.

  1. Я великий шанувальник сказати саме те, що я маю на увазі, особливо у вихідному коді. Новачку доведеться шукати визначення мінусів лише один раз, але потім читати і використовувати це тисячу разів. Я вважаю, що в довгостроковій перспективі приємніше працювати з системами, які полегшують звичайний випадок, навіть якщо попередня вартість трохи вище.

  2. Те, що це було б "безглуздо" для людей, які не мають досвіду ПП, насправді є великою перевагою. Як ви зазначали, всі інші знайдені вами слова вже мають певне значення, і це значення є дещо іншим або неоднозначним. У новому понятті має бути нове слово (або в цьому випадку старе). Я вважаю за краще, щоб хтось шукав визначення мінусів, ніж припускати неправильно, що він знає, що робить Add.

  3. Інші операції, запозичені з функціональних мов, часто зберігають свої оригінальні назви, без явних катастроф. Я не бачив жодного поштовху придумати синоніми "карта" та "зменшити", які звучать більш звично для не-FPers, і я не бачу ніякої користі від цього.

(Повне розкриття: Я програміст Ліспа, тому я вже знаю, що означає Мінуси.)


16
Не забувайте, що відкриття є важливим, якщо я набираю "testSuite". і переглянувши список методів, я хотів би побачити метод, який підказує правильну річ. Я, мабуть, не шукатиму безглуздого (для мене) імені на зміну - це те, що я хочу.
Джон Скіт

33
Якщо я відчував себе химерним, я б застосував метод Add, який просто кинув виняток з message = "Використовувати мінуси, щоб додати до ImmutableList". :-)
Кен

2
Це нікого не вб’є, прочитавши кілька рядків коментарів, де пояснюється, чому це ім'я, і ​​посилається на їх, скажімо, "Структура та інтерпретація комп'ютерних програм" Абельсона та Суссмана.
Джон Р. Стром

16
Традиційно мінуси додають на початку, а не в кінці. Тож це потенційно оманлива назва описаного методу.
walkytalky

16
Тільки щоб зберегти наступного нефункціонального програміста на клацання або 3 ... en.wikipedia.org/wiki/Cons від слова "сконструювати", вираз "перевести x на y" означає побудувати новий об'єкт з ( мінуси xy)
Містер

59

Насправді мені подобається And, особливо ідіоматично. Особливо мені сподобається, якби у вас було статичне властивість лише для перегляду порожнього списку, і, можливо, зробити конструктор приватним, так що вам завжди доведеться будувати з порожнього списку.

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

Мені подобається ідея Порожня. Досі не переконаний у І хоча. Це просто крихітка.
Джон Скіт

Це просто більше схоже на те, як я б подумав над створенням списку речей природною мовою. Якщо ви читаєте його вголос, це здається більш інтуїтивним, ніж Додати або Плюс. "list" - це порожній список і "Hello" і "Immutable" та "Word". Я погодився б, що це менш ясно в ізоляції.
tvanfosson

52

Кожного разу, коли я перебуваю в варенні з номенклатурою, я забиваю інтербети.

thesaurus.com повертає це для "додати":

Визначення: примикати, збільшувати; зробити додатковий коментар

Синоніми: афікс, додаток, анте, додати, збільшити, яловичину, збільшити, наростити, заряджати, продовжувати, кидатись, фігурувати, вилуплювати, нагрівати, походити, підходити, зачіпляти, зачіпляти, підключити з, включити, підключити, джаз вгору, об'єднатися разом, колодка, парламент, косичка, підключити, залити його, відповісти, бігти вгору, сказати далі, ляпати, сніжний ком, суп, пришвидшити, шип, піднятися, доповнювати, підсолоджувати, приставляти, мітити

Мені подобається звук Adjoinабо, простіше кажучи Join. Це те, що ти робиш, правда? Метод також може бути застосований до приєднання інших ImmutableList<>осіб.


1
Мені так само подобається "Приєднатися", але в більшості випадків, коли ви приєднуєтесь до 2 об'єктів, ви отримуєте 1. У цьому випадку, якщо ви приєднуєтесь до 2 об'єктів, ви фактично створюєте новий об'єкт.
Програматор поза законом

1
Я не знаю жодних випадків у .NET, Perl, PHP або навіть VBScript, де Join передбачає мутацію. Конструкція така, що A і B приєднуються до створення C, де C завжди нова сутність.
подружжя

Мені подобається приєднатися, і я цілком погоджуюся з thesaurus.com :) Використовуйте це весь час, коли сумніваєтесь у назві.
Скурмедель

var suite = новий TestSuite <string, int> () .Join (x => x.Length);
Хитрий Грифон

3
Ідіть з Piggyback, imo. Або HookUpWith.
Кріс Марасті-Георг

48

Особисто мені подобається .With (). Якби я використовував об’єкт, прочитавши документацію або коментарі до коду, було б зрозуміло, що він робить, і він зчитує нормально у вихідному коді.

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

Або ви додаєте "Разом" з ним .. :)

object.AlongWith("this new item");

+1. "З" - це оператор інфікування в SETL, який робить те саме. Якщо SETL використовує його, то він повинен бути правильним :-)
finnw

1
Ба ... хто більше використовує VB? :) Ага .. Опс .. Це було вголос? хе .. Але, ні, з усією серйозністю, тому я вважав "Разом з", що усуне проблему VB. Існує лише близько мільйона різних способів, якими він міг би пройти цим ... я маю на увазі, навіть божевільні, як-от: object.Plus () або Object.ExistingPlus () ... і т. Д. Це чортово добре питання опубліковано, однак ... хе ..
LarryF

33

В кінцевому підсумку я пішов з Add для всіх своїх незмінних колекцій у BclExtras . Причина в тому, що це легко передбачувана назва. Я не так хвилююся, що люди плутають додаток з мутуючим додаванням, оскільки ім'я типу з префіксом Immutable.

Деякий час я розглядав мінуси та інші назви функціональних стилів. Врешті-решт я знизив їх, бо вони не так добре відомі. Звичайно, функціональні програмісти зрозуміють, але вони не більшість користувачів.

Інші імена: ви згадали:

  • Плюс: я бажаю / миюсь на цьому. Для мене це не відрізняє це як не мутаційну операцію більше, ніж Add
  • З: Викличе проблеми з VB (призначений каламбур)
  • Перевантаження оператора: проблема виявлення може бути проблемою

Я розглядав варіанти:

  • Concat: String's є незмінними і використовують це. На жаль, це дійсно добре для додавання до кінця
  • CopyAdd: скопіювати що? Джерело, список?
  • AddToNewList: Можливо, це хороший список. А як щодо колекції, стека, черги тощо ...

На жаль, насправді, здається, немає слова

  1. Однозначно незмінна операція
  2. Зрозуміло для більшості користувачів
  3. Представлений менш ніж у 4 словах

Це стає ще більш дивним, якщо розглядати колекції, крім List. Візьмемо для прикладу стек. Навіть програмісти першого року можуть сказати вам, що в стеках є пара методів Push / Pop. Якщо ви створюєте ImmutableStack і даєте йому зовсім інше ім’я, давайте назвати його Foo / Fop, ви тільки що додали більше роботи для використання вашої колекції.

Редагувати: відповідь на Plus Edit

Я бачу, куди ви їдете з Плюсом. Я думаю, що більш вагомим випадком буде насправді мінус для видалення. Якби я побачив наступне, я б точно задумався, що в світі думав програміст

list.Minus(obj);

Найбільша проблема у мене з Plus / Minus або новим сполученням - це відчуття перенасиченості. Сама колекція вже має відмітну назву, префікс Immutable. Навіщо йти далі, додаючи словниковий запас, метою якого є додати те саме відмінність, що і префікс Immutable.

Я бачу аргумент сайту виклику. Це робить більш зрозумілим з точки зору одного виразу. Але в контексті всієї функції це видається непотрібним.

Редагувати 2

Погодьтеся, що String.Concat і DateTime.Add, безумовно, збентежили людей. Я бачив, як кілька дуже яскравих програмістів потрапили на цю проблему.

Однак я думаю, що ImmutableList - інший аргумент. Ніщо про String або DateTime не визначає програму програміста як Незмінного. Ви просто повинні знати, що це незмінне через якесь інше джерело. Тож плутанина не є несподіваною.

У ImmutableList немає такої проблеми, оскільки назва визначає її поведінку. Ви можете стверджувати, що люди не знають, що таке незмінне, і я думаю, що це також справедливо. Я, звичайно, не знав цього приблизно до 2 року в коледжі. Але у вас є те саме питання з будь-яким ім'ям, яке ви виберете замість Add.

Редагувати 3: Що з типами типу TestSuite, які незмінні, але не містять цього слова?

Я думаю, що це приводить додому ідею, що ви не повинні вигадувати нові назви методів. А саме тому, що явно є прагнення зробити типи непорушними, щоб полегшити паралельні операції. Якщо ви зосередитесь на зміні назви методів для колекцій, наступним кроком стануть мутаційні назви методів для кожного використовуваного типу, який є незмінним.

Я думаю, що було б більш цінним зусиллям замість того, щоб зосередитись на тому, щоб типи ідентифікувалися як Незмінні. Таким чином ви зможете вирішити проблему, не переосмислюючи кожен мутаційний зразок методу.

Тепер, як можна визначити TestSuite як незмінний? Я думаю, що в сучасних умовах існує кілька способів

  1. Префікс з Immutable: ImmutableTestSuite
  2. Додайте атрибут, який описує рівень Імутаблітії. Це, звичайно, менш відкрито
  3. Не багато іншого.

Моя здогадка / сподівання, що інструменти розробки почнуть допомагати цій проблемі, полегшивши визначити непорушні типи просто за допомогою зору (різний колір, сильніший шрифт тощо). Але я думаю, що це відповідь, хоча через зміну всіх назв методів.


Я додав причини мого переваги Plus над Додати до питання. Буду вітати коментарі з цього приводу. Я справді відкритий до думки, що я дурний.
Джон Скіт

@JaredPar: А як бути, якщо тип називається TestSuite?
Джон Скіт

Хочеться дати ще один +1 для редагування 3, але, очевидно, не може. (У моєму випадку я не намагаюся домогтися паралелізму - я вважаю, що незмінність призводить до коду, про який легше міркувати.) Я все ще не зовсім впевнений, що Add - це шлях, але підтримка у відповідях тут є переконливим.
Джон Скіт

Якщо у вас може трапитися це питання на розмову на роботі, це теж буде приголомшливо, btw. Я розпочав дискусію за списком C #, тому деякі колеги можуть вже брати участь. Можна також запитати всередині Google…
Джон Скіт,

@Jon, я думаю, що я знаю, як добре
зупинити

27

Я думаю, що це може бути однією з тих рідкісних ситуацій, коли допустимо перевантажувати +оператора. У математичній термінології ми знаємо, що +не додає щось до кінця чогось іншого. Він завжди поєднує два значення разом і повертає нове отримане значення.

Наприклад, інтуїтивно очевидно, що коли ти кажеш

x = 2 + 2;

отримане значення x дорівнює 4, а не 22.

Аналогічно

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

має чітко визначити, що має містити кожна змінна. Повинно бути зрозуміло, що в останньому рядку list2це не змінюється , а замість цього list3присвоюється результат додавання "слова" до list2.

В іншому випадку я б просто назвав функцію Plus ().


Що робити, якщо у вас є загальний список, до якого ви могли б законно додати ціле число (скажімо) або інший список цілих чисел? Тоді це використання + суперечить конкатенації.
finnw

@finnw: Я не бачу вашої точки зору. Зі списком я б завжди очікував + означати додавання, додавши ви один елемент чи кілька.
Білл Ящірка

4
Для API для багаторазового використання добре також мати метод з назвою, якщо хтось використовує ваш клас з мови без перевантаження оператора.
Ніл

"додаєте ви один елемент чи кілька" - що робити, якщо ви хочете додати список як один елемент? тобто, [1] + 2 = [1,2]але [1] + [2] = [1,[2]]. Те, що ви пропонуєте, - це непослідовна поведінка. Можливо, тому Python не дозволяє вам додати один елемент таким чином.
10.10

Ну, на мові зі статичним типом, як C #, ви можете сказати, що таке тип елементів списку, чи це список списків або список елементів, тож ви можете використовувати тип, щоб вирішити, додавати один елемент, який є списком, або об'єднати два списки.
Dobes Vandermeer

22

Щоб бути максимально зрозумілим, можливо, ви захочете піти з дурнем CopyAndAddабо чимось подібним.


Не у всіх незмінних колекціях потрібна копія, яку потрібно додати. Подумайте про непорушні дерева, їм просто потрібен новий вузол і вони можуть використовувати існуюче дерево як листя.
JaredPar

До речі, я читав ваш профіль, а потім старів і коротко дивувався тому, скільки тобі років. Невдовзі пізніше розсунувся Саніт.
JaredPar

Знову перший коментар: я використовую дерева так рідко, що така думка мені ніколи не спадала на думку. Це хороший момент.
Майкл Майерс

Знову другий коментар: Зізнаюсь, я це зробив за значком! Я просто не люблю видавати свій вік. (Я насправді молодший за вас, але я можу досить добре зіграти в крокетчі старожила, якщо мені потрібно. І я не єдиний, чий вік вказаний як 89.)
Майкл Майерс

Аргумент непорушних дерев є сильним, хорошим моментом. Тоді EquivalentReferenceWithAdded (x) би боровся з цим аргументом, але звучить нерозумно і важко вивести.
TheBlastOne

21

Я б назвав це Extend () або, можливо, ExtendWith (), якщо ви відчуваєте, що справді багатослівний.

Розширення означає додавання чогось іншого, не змінюючи цього. Я думаю, що це дуже актуальна термінологія в C #, оскільки це схоже на поняття методів розширення - вони "додають" новий метод до класу, не "торкаючись" самого класу.

В іншому випадку, якщо ви дійсно хочете підкреслити, що ви взагалі не змінюєте оригінальний об'єкт, використання якогось префікса типу Get- мені здається неминучим.


1
Але все-таки має на увазі щось робити з базовим об'єктом.
хаос

18

Додано (), додано ()

Мені подобається використовувати минулий час для операцій над незмінними об'єктами. Він передає думку про те, що ви не змінюєте початковий об'єкт, і його легко розпізнати, коли ви його бачите.

Крім того, оскільки назви методів, що мутують, часто є дієсловами, що перебувають у напруженому часі, він застосовується до більшості випадків, у яких ти потребуєш незмінний метод-ім'я. Наприклад, незмінний стек має методи "висунутий" і "вискочив".


1
Python також використовує цю умову. Наприклад, вбудовані функції перевернуті () та відсортовані ().
Джо

18

Мені подобається пропозиція mmyers від CopyAndAdd . Відповідно до теми "мутації", можливо, ви могли б перейти з Bud (безстатеве розмноження), Grow , Replicate або Evolve ? =)

EDIT: Щоб продовжити мою генетичну тему, як щодо Procreate , маючи на увазі, що створюється новий об’єкт, який базується на попередньому, але додається щось нове.


14

Це, мабуть, розтягнення, але в Рубі є часто використовувані позначення для розрізнення: addне мутує; add!мутує. Якщо це поширена проблема у вашому проекті, ви можете зробити це теж (не обов'язково з не алфавітними символами, але послідовно використовуючи позначення для позначення методів, що мутують / не мутують).


+1. це не виконується мовою, а узгоджується як конвенція. Мені це подобається.
ома


13

Можливо, плутанина випливає з того, що потрібно дві операції в одній. Чому б не розділити їх? Стиль DSL:

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

Copyповерне проміжний об'єкт, це змінна копія оригінального списку. Withповерне новий незмінний список.

Оновлення:

Але проміжна колекція, що змінюється, не є гарним підходом. Проміжний об'єкт повинен міститися в Copyоперації:

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

Тепер Copyоперація бере делегата, який отримує список, що змінюється, щоб він міг контролювати результат копіювання. Це може зробити набагато більше, ніж додавання елемента, як-от видалення елементів або сортування списку. Він також може бути використаний в ImmutableListконструкторі для складання початкового списку без посередницьких незмінних списків.

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

Тепер немає можливості неправильного тлумачення з боку користувачів, вони, природно, потраплять у яму успіху .

Ще одне оновлення:

Якщо ви все ще не любите згадку про змінний список, навіть зараз, коли він міститься, ви можете створити об'єкт специфікації, який буде визначати або сценарій , як операція копіювання перетворить його список. Використання буде таким же:

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

Тепер ви можете бути творчими з іменами правил, і ви можете лише розкрити функціонал, який ви хочете Copyпідтримувати, а не всі можливості програми IList.

Для використання ланцюга можна створити розумний конструктор (який, звичайно, не використовуватиме ланцюжок):

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

...

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

Або використовувати того ж делегата в іншому конструкторі:

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

Це передбачає, що rules.Appendметод повертається this.

Ось як це виглядатиме з вашим останнім прикладом:

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

@Jordao: Тому що такий склад призводить до набагато простішої форми ініталізації. Чому є дві окремі змінні, коли я хочу лише одну? Так само я не хочу створювати змінну копію - я хочу, щоб все було незмінним протягом усього часу, оскільки це призводить до коду, про який легше міркувати, IMO.
Джон Скіт

Все це все-таки є більш громіздким, ніж "Плюс" і т. Д. Дякую за ідеї, що стосуються мутації, але я, безумовно, віддаю перевагу підходу "тримати його незмінним".
Джон Скіт

Можливо, тоді завжди будуть неправильні тлумачення того, що таке реальна семантика операції. Якщо ви будете слідувати маршруту об'єкта специфікації, мутація не відбувається (принаймні, зовні), об'єкт лише визначає, як буде виглядати новий незмінний об'єкт. У вас є операція, яка переходить від одного незмінного об'єкта до іншого, і оскільки він називається Копіювати, для непорозумінь немає місця.
Йордао

Єдині імена, які могли б працювати для вас, здаються складними іменами, як-от CopyAndAppend, CopyAndAdd тощо
Jordão

1
Я фактично зростаю прихильником цього підходу (з усіма правками) як API для незмінних колекцій. Однак я заперечую, що поєднання цього підходу з допоміжними методами для стандартних специфікацій, наприклад, Concat, пропонує найкраще для обох світових.
конопля

11

Кілька випадкових думок:

  • ImmutableAdd ()
  • Додати ()
  • Конструктор ImmutableList <T> (ImmutableList <T> originalList, T newItem)

1
+1 для ImmutableAdd; не захоплюється додатком (надто схожий на StringBuilder.Append, який мутує), а версія конструктора - це біль у плані ланцюга.
Джон Скіт

10

DateTime в C # використовує Додати. То чому б не використати те саме ім’я? Поки користувачі вашого класу розуміють, що клас непорушний.


Я б заперечував, що DateTime.Add, як відомо, плутає людей ... але я згоден, це показує перевагу.
Джон Скіт

1
Так само, як методи мутації рядка бентежать нових розробників. Але досить скоро всі дізнаються, що "струни незмінні"
Пн

9

Я думаю, що ключовим, що ви намагаєтеся досягти, що важко виразити, є непермутація, тому, можливо, щось із генеративним словом у ньому, щось на зразок CopyWith () або InstancePlus ().


9

Я не думаю, що англійська мова дозволить вам наводити незмінність безпомилково під час використання дієслова, що означає те саме, що і "Додати". "Плюс" майже це робить, але люди все ж можуть помилитися.

Єдиний спосіб заборонити вашим користувачам помиляти об’єкт на щось змінне - це зробити його явним або через ім'я самого об'єкта, або через ім'я методу (як у паралельних варіантах типу "GetCopyWith" або "CopyAndAdd").

Тому просто зайдіть з улюбленим "Плюсом".


9

По-перше, цікавий вихідний пункт: http://en.wikipedia.org/wiki/Naming_conventions_(programming) ... Зокрема, перевірте посилання "Дивіться також" внизу.

Я виступаю за Плюс або І, фактично однаково.

Плюс та І обидва математики базуються в етимології. Отже, обидва означають математичну операцію; обидва дають вираз, який природним чином читається як вирази, які можуть перетворитися на значення, що відповідає методу, що має зворотне значення. Andмає додаткову логічну конотацію, але обидва слова інтуїтивно застосовуються до списків. Addконотує дію, що виконується на об'єкті, що суперечить незмінній семантиці методу.

Обидва вони короткі, що особливо важливо з огляду на примітивність операції. Прості, часто виконувані операції заслуговують на коротші назви.

Висловлення незмінної семантики - це те, що я вважаю за краще робити через контекст. Тобто я скоріше просто маю на увазі, що весь цей блок коду має функціональне відчуття; припустимо, що все незмінне. Це, можливо, просто я. Я вважаю за краще незмінність як правило; якщо це зроблено, робиться багато в тому ж місці; Мінливість є винятком.


8

Як щодо Chain () або Attach ()?


1
Додаток, безумовно, звучить як мутування. Можливо, WithAttached було б мудрішим, але він дуже близький до WithAdded, про який було сказано вище.
TheBlastOne

Смішно, скільки разів згадується "прикування" в описі того, що намагаються зробити з цим. (5 разів), але не пропонується як пропозиція! Це перше, що з’явилось visualthesaurus.com(без належності), коли я шукав concatenate.
cod3monk3y

7

Я віддаю перевагу Плюс (і Мінус). Їх легко зрозуміти і відображати безпосередньо в операціях, що включають добре відомі незмінні типи (числа). 2 + 2 не змінює значення 2, воно повертає нове, однаково незмінне значення.

Деякі інші можливості:

Сплайс ()

Трансплантат ()

Бетон ()


6

Як щодо матерів , матерів чи коїтусів для тих, хто перебуває. З точки зору розмноження ссавці, як правило, вважаються непорушними.

Збираюся викинути Союз і там. Позичені у SQL.


2
+1 для Union. Я, однак, запозичую його безпосередньо з теорії множин. :-)
Крістоффер Летте

Чи не SQL отримує велику частину своєї термінології з теорії множин?
Джейсон Д

1
Крім того, Union передбачає відмінність. Якщо ви хочете включити дублікати (принаймні в TSQL), вам потрібно використовувати Union All явно.
конопля

6

Мабуть, я перший Obj-C / какао, який відповів на це питання.

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

З цим не збирається вигравати будь-які ігри в гольф.


+1, [object]By[Verb]ing[Object]:префікс методу означає, що новий рядок буде повернуто на відміну від просто [verb][Object]:, що мітувало б об'єкт на місці.
Дейв ДеЛонг

3
+1. Я не розумію відрази людей до багатослівності (також самодокументації).
хеніч

5

Я думаю, що "Додати" або "Плюс" звучить чудово. Назви самого списку має бути достатньо, щоб передати незмінність списку.


Це не список, це тестовий набір.
tstenner

5

Можливо, є кілька слів, які мені більше запам'ятовують копію та додають до цього речі замість того, щоб мутувати екземпляр (наприклад, "Concatenate"). Але я думаю, що було б добре мати симетричність цих слів для інших дій. Я не знаю подібного слова "Видалити", яке я думаю, такого ж типу, як "З'єднати". "Плюс" для мене звучить трохи дивно Я б не очікував, що він буде використовуватися в нечисловому контексті. Але це могло виникнути і з мого неанглійського походження.

Можливо, я б скористався цією схемою

AddToCopy
RemoveFromCopy
InsertIntoCopy

Однак у них є свої проблеми, коли я думаю про це. Можна подумати, що вони щось видаляють або додають щось до наведеного аргументу. Не впевнений у цьому взагалі. Ці слова теж не грають приємно, якщо я прикутий. Занадто багатослівний для набору.

Можливо, я просто використав би просто "Додати" та друзів. Мені подобається, як він використовується в математиці

Add 1 to 2 and you get 3

Ну, звичайно, 2 залишається 2, і ви отримуєте нове число. Йдеться про два числа, а не про список та елемент, але я думаю, що це має певну аналогію. На мою думку, addце не означає, що ти щось мутуєш. Я, безумовно, бачу ваше твердження, що мати самотнє твердження, що містить просто addі не використовувати повернутий новий об’єкт, не виглядає баггі. Але зараз я також подумав деякий час про цю ідею використання іншого імені, ніж "додати", але я просто не можу придумати інше ім'я, не змушуючи мене думати "хм, мені потрібно було б переглянути документацію, щоб знати, що мова йде про "тому, що його назва відрізняється від того, що я б очікував назвати" додати ". Просто деякі дивні думки про це з лампа, не впевнені, що це має сенс взагалі :)


Але копія не завжди потрібна в незмінній колекції. Візьмемо, наприклад, бінарне дерево. Додавання нового кореня не потребує копіювання, лише нове значення, коли одним із листя є старе дерево
JaredPar

KISS - Якщо іменування почало включати деталі реалізації, всі назви методів стали би занадто довгими. "додати" досить просто і робить роботу.
мП.

1
@mP: Знову ви використовуєте словосполучення "деталі реалізації" у спосіб, який, на мою думку, є непридатним. Незалежно від того, що це зв'язаний список чи масив під кришкою, це деталь реалізації . Я міг змінити реалізацію, не змінюючи API. Незмінний аспект не є деталізацією реалізації.
Джон Скіт

1
правильно. JaredPar, але я думаю, що також не важливо, чи воно насправді копіює дерево або просто використовує існуюче дерево та використовує його як лист для повернення нового дерева. я маю на увазі, що це лише деталь реалізації. це те саме для (я вважаю) операції з підрядкою для строкового класу java.
Йоханнес Шауб - ліб


5

Я думаю, що це Plus()і, Minus()або, альтернативно Including(), Excluding()є розумним, коли мається на увазі незмінна поведінка.

Однак жоден вибір імен не зробить це абсолютно зрозумілим для всіх, тому я особисто вважаю, що хороший коментар документа xml пройде дуже довгий шлях. VS кидає це вам прямо в обличчя, коли ви пишете код в IDE - їх важко ігнорувати.


4

Append- тому що зауважте, що назви System.Stringметодів говорять про те, що вони мутують екземпляр, але вони цього не роблять.

Або мені дуже подобається AfterAppending:

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

Як і DateTime аргумент раніше, я згоден з старшинства , якби не той факт , що так багато програмісти дійсно очікують рядкові методи , щоб робити речі. Їм доводиться говорити (іноді повторно), що струни незмінні. Я хотів би заманювати своїх розробників-клієнтів у яму успіху :)
Джон Скіт

Мені подобається Додавати все більше і більше. Це відрізняє те, що ви не мутуєте колекцію, а приєднуєтесь до неї.

4

list.CopyWith(element)

Як і Smalltalk :)

А також, list.copyWithout(element)що видаляє всі виникнення елемента, що найкорисніше, коли використовується list.copyWithout(null)для видалення невстановлених елементів.


3

Я б пішов на Add, тому що я бачу перевагу кращого імені, але проблема полягає в тому, щоб знайти різні назви для кожної іншої непорушної операції, яка може зробити клас зовсім незнайомим, якщо це має сенс.


Так, я бачу вашу думку. Я думаю, що я все ще віддаю перевагу Плюсу, але це питання, який варто задуматися.
Джон Скіт

Дякую, Джон. Я з нетерпінням чекаю використання вашої основи. Я просто читав про це, і це виглядає дуже добре. Знову дякую.
Джоан Венге
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.