Какое имя лучше всего использовать для неизменяемого метода add в неизменяемой коллекции?


229

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

Предположим, у меня есть неизменный тип списка. У него есть операция, Foo(x)которая возвращает новый неизменный список с указанным аргументом в качестве дополнительного элемента в конце. Таким образом, для построения списка строк со значениями «Hello», «immutable», «world» вы можете написать:

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

Мой вопрос: как лучше назвать Foo?

РЕДАКТИРОВАТЬ 3 : Как я покажу позже, имя типа может на самом деле не быть ImmutableList<T>, что делает позицию ясной. Вместо этого представьте, что он TestSuiteи что он неизменен, потому что весь фреймворк, частью которого он является, неизменен ...

(Конец редактирования 3)

Варианты, которые я придумала до сих пор:

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

Критерии, которые я использую для выбора:

  • Дает правильное представление о результате вызова метода (то есть, что это оригинальный список с дополнительным элементом)
  • Делает это настолько ясным, насколько это возможно, что он не изменяет существующий список
  • Звучит разумно, когда объединены в цепочку, как во втором примере выше

Пожалуйста, попросите более подробную информацию, если я не проясняю себя достаточно ...

EDIT 1: Вот мои рассуждения для предпочитая , Plusчтобы Add. Рассмотрим эти две строки кода:

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

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

РЕДАКТИРОВАТЬ 2: Причины не нравится Добавить.

По сути, существуют разные ответы: «Идите с Add. Вот что DateTimeделает, и Stringимеет Replaceметоды и т . Д., Которые не делают неизменность очевидной». Я согласен - здесь есть приоритет. Тем не менее, я видел много людей называют DateTime.Addили String.Replaceи ожидать мутации . Есть множество вопросов группы новостей (и, вероятно, SO, если я копаюсь), на которые отвечают: «Вы игнорируете возвращаемое значение 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
@ Адам: Нет, последний явно глючит. Они оба на самом деле багги ( так как они не делают ничего с результатом) - но первый не выглядеть багги для меня.
Джон Скит

36
Является ли кошка собакой?
Майкл Майерс

7
Concat / Condog ... работает на меня! ;)
gnovice

11
Uncat - это был бы зомби-кот.
Эрик Форбс

2
@Trap: Это отстой с точки зрения создания API API, хотя.
Джон Скит

Ответы:


130

В таких ситуациях я обычно иду Concat. Это обычно подразумевает для меня, что создается новый объект.

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

3
Это то, что я использую, потому что это то, что использует System.Linq.Enumerable - решение уже принято. :) Я не могу быть единственным человеком, который определил свою собственную перегрузку расширения Concat в IEnumerable, чтобы принять одно значение для добавления.
Дэниел Эрвикер

9
+1 Это правильный ответ для поддержания согласованности имен в рамках.
Сэм Харвелл

Если я не пропустил это, System.Linq.Enumerable (и Linq в целом) использует Concat () только для «sequence + sequence», а не «item + sequence». Проблема в том, что кто-то «может ожидать, что он добавит два списка вместе, а не добавит одно значение в другой список», был явно указан как причина не использовать один из других оригинальных параметров.
Ssswift

119

Я бы пошел с минусами по одной простой причине: это означает именно то, что вы хотите.

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

  2. Тот факт, что это было бы «бессмысленно» для людей без опыта FP, на самом деле является большим преимуществом. Как вы указали, все остальные слова, которые вы нашли, уже имеют какое-то значение, и это значение немного отличается или неоднозначно. Новая концепция должна иметь новое слово (или, в данном случае, старое). Я бы предпочел, чтобы кто-то посмотрел определение «против», чем предположил, что он неправильно знает, что делает «Ад»

  3. Другие операции, заимствованные из функциональных языков, часто сохраняют свои оригинальные имена, без явных катастроф. Я не видел никакого толчка, чтобы придумать синонимы для «map» и «lower», которые звучат более знакомо не-FPers, и я не вижу никакой выгоды от этого.

(Полное раскрытие: я программист на Лиспе, так что я уже знаю, что означает «Против».)


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

33
Если бы я чувствовал себя странно, я бы сделал метод Add, который просто вызывал бы исключение с message = "Использовать Cons для добавления в ImmutableList". :-)
Кен,

2
Никто не убьет, если прочтет несколько строк комментариев, объясняющих, почему это имя, и ссылается, скажем, на «Структура и интерпретация компьютерных программ» Абельсона и Суссмана.
Джон Р. Штром

16
Традиционно минусы добавляют в начале, а не в конце. Так что это потенциально вводящее в заблуждение название для описанного метода.
walkytalky

16
Просто чтобы сохранить следующего неработающего программиста одним щелчком или 3 ... en.wikipedia.org/wiki/Cons из слова «конструировать», выражение «превратить х в у» означает создание нового объекта с помощью ( минусы ху)
Myster

59

На самом деле мне нравится And, особенно идиоматическим способом. Мне бы особенно понравилось, если бы у вас было статическое свойство readonly для пустого списка, и, возможно, вы сделали конструктор закрытым, чтобы вам всегда приходилось строить из пустого списка.

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

Мне нравится Пустая идея. Все еще не убежден в И хотя. Это просто немного бла.
Джон Скит

Это просто больше похоже на то, как я думаю о создании списка вещей на естественном языке. Если вы читаете это вслух, это кажется более интуитивным, чем «Добавить» или «Плюс». «list» - это пустой список, а также «Hello», «Immutable» и «Word». Я согласился бы, что это менее ясно в изоляции, хотя.
tvanfosson

52

Всякий раз, когда я нахожусь в варенье с номенклатурой, я попадаю в сети.

thesaurus.com возвращает это для «добавить»:

Определение: соприкосновение, увеличение; сделать дальнейший комментарий

Синонимы: аффикс, приложение, анте, добавление, увеличение, усиление, повышение, наращивание, зарядка, продолжение, наведение, фигура, выделение, нагрев, поход, повышение, зацепление, зацепление, зацепление с, включают, поднять, взбодрить, объединить, колодки, parlay, контрейлерных, подключи, залить его, ответить, разбежаться, скажем дальше, хлопнуть, снежный ком, суп, ускорить, всплеск, шаг вверх, добавка, подсластить, прихватить, тег

Мне нравится звук Adjoin, или более просто Join. Это то, что ты делаешь, верно? Этот метод может также применяться для присоединения к другим ImmutableList<>.


1
Мне также нравится «Присоединиться», но в большинстве случаев, когда вы объединяете 2 объекта, вы получаете 1. В этом случае, если вы объединяете 2 объекта, вы фактически создаете новый объект.
Outlaw Programmer

1
Я не знаю ни одного случая в .NET, Perl, PHP или даже VBScript, где Join подразумевает мутацию. Конструкция такова, что A и B объединяются, чтобы создать C, где C всегда новый объект.
Спулсон

Мне нравится Join, и я полностью согласен с thesaurus.com :) Используйте это все время, когда сомневаетесь в имени.
Skurmedel

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

3
Иди с Piggyback, IMO. Или HookUp с.
Крис Марасти-Георг

48

Лично мне нравится .With (). Если бы я использовал объект, после прочтения документации или комментариев к коду, было бы понятно, что он делает, и он хорошо читается в исходном коде.

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

Или вы добавляете "Вместе" с этим .. :)

object.AlongWith("this new item");

+1. «WITH» - это инфиксный оператор в SETL, который делает то же самое. Если SETL использует это, то это должно быть правильно :-)
finnw

1
Бах ... Кто больше использует VB? :) Эээ ... Оппс ... Это было вслух? хех .. Но, нет, со всей серьезностью, поэтому я рассмотрел «AlongWith», который бы убрал проблему VB. Есть только около миллиона различных способов, которыми он мог бы пойти с этим ... Я имею в виду, даже безумные, такие как: object.Plus () или Object.ExistingPlus () ... и т.д ... Это чертовски хороший вопрос, он опубликовано, однако ... хе ..
LarryF

33

В итоге я выбрал « Добавить» для всех моих неизменных коллекций в BclExtras . Причина в том, что это легко предсказуемое имя. Я не очень беспокоюсь о людях, которые путают Add с мутировавшим add, так как имя типа имеет префикс Immutable.

Некоторое время я обдумывал «против» и другие названия функциональных стилей. В конце концов я обесценил их, потому что они не так хорошо известны. Конечно, функциональные программисты поймут, но они не большинство пользователей.

Другие имена: вы упомянули:

  • Плюс: я хочу / стираю на этом. Для меня это не отличает его от того, что он не является мутирующей операцией больше, чем Add
  • С: вызовет проблемы с VB (каламбур)
  • Перегрузка оператора: проблема с обнаружением

Варианты, которые я рассматривал:

  • Concat: строки неизменны и используют это. К сожалению, это действительно хорошо только для добавления в конец
  • CopyAdd: Скопировать что? Источник, список?
  • AddToNewList: Может быть, хороший для списка. Но как насчет коллекции, стека, очереди и т. Д ...

К сожалению, на самом деле, кажется, нет слова, которое

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

Это становится еще более странным, когда вы рассматриваете коллекции, отличные от List. Возьмите, например, стек. Даже программисты первого года могут сказать вам, что в стеках есть пара методов Push / Pop. Если вы создаете ImmutableStack и даете ему совершенно другое имя, назовем его Foo / Fop, вы просто добавили больше работы для них, чтобы использовать вашу коллекцию.

Редактировать: Ответ на Плюс Редактировать

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

list.Minus(obj);

Самая большая проблема, с которой я сталкиваюсь с плюсом / минусом или новым сочетанием, - это чувство переполненности. Сама коллекция уже имеет отличительное имя, неизменный префикс. Зачем идти дальше, добавляя словарь, цель которого - добавить то же различие, что и префикс Immutable.

Я вижу аргумент вызова сайта. Это делает это более понятным с точки зрения одного выражения. Но в контексте всей функции это кажется ненужным.

Редактировать 2

Согласитесь, что люди определенно смущены String.Concat и DateTime.Add. Я видел несколько очень ярких программистов, решивших эту проблему.

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

ImmutableList не имеет этой проблемы, потому что имя определяет его поведение. Можно утверждать, что люди не знают, что такое Неизменное, и я думаю, что это также верно. Я, конечно, не знал об этом примерно до 2 года в колледже. Но у вас та же проблема с любым именем, которое вы выберете вместо «Добавить».

Изменить 3: Как насчет типов, таких как TestSuite, которые являются неизменными, но не содержат слово?

Я думаю, что это наводит на мысль, что вы не должны изобретать новые имена методов. А именно потому, что явно существует стремление сделать типы неизменяемыми для облегчения параллельных операций. Если вы сосредоточитесь на изменении имени методов для коллекций, следующим шагом будет изменение имен методов для каждого используемого вами типа, который является неизменным.

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

Теперь, как вы можете определить TestSuite как неизменный? В сегодняшней среде я думаю, что есть несколько способов

  1. Префикс с неизменным: ImmutableTestSuite
  2. Добавьте Атрибут, который описывает уровень Immutablitiy. Это, безусловно, менее заметно
  3. Не намного больше.

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


Добавили причины моего предпочтения для Plus над Добавить к вопросу. Приветствую комментарии по этому поводу Я действительно открыт для мысли, что я глупый.
Джон Скит

@JaredPar: А если тип называется TestSuite?
Джон Скит

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

Если бы вы могли вставить этот вопрос в разговор на работе, это тоже было бы здорово. Я начал обсуждение списка C #, поэтому некоторые коллеги могут быть уже вовлечены. Можно спросить и в Google тоже ...
Джон Скит

@ Джон, я думаю, я знаю хорошее место, чтобы
оставить

27

Я думаю, что это может быть одной из тех редких ситуаций, когда допустимо перегрузить +оператора. В математической терминологии мы знаем, что +это не добавляет что-то к концу чего-то другого. Он всегда объединяет два значения вместе и возвращает новое результирующее значение.

Например, очевидно, что когда вы говорите,

x = 2 + 2;

результирующее значение х равно 4, а не 22.

Так же,

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

Должно быть ясно, что каждая переменная будет содержать. Должно быть понятно, что list2не изменяется в последней строке, а вместо этого list3присваивается результат добавления слова list2.

В противном случае я бы просто назвал функцию Plus ().


Что если у вас есть общий список, к которому вы могли бы законно добавить целое число (скажем) или другой список целых чисел? Тогда это использование + будет конфликтовать с конкатенацией.
финн

@finnw: я не понимаю твою точку зрения. Со списком я всегда ожидал бы, что + будет означать добавление, добавляете ли вы один элемент или несколько.
Билл Ящерица

4
Для API многократного использования неплохо также иметь именованный метод на тот случай, если кто-то использует ваш класс из языка без перегрузки операторов.
Нил

«добавляете ли вы один элемент или несколько» - что, если вы хотите добавить список как один элемент? то есть, [1] + 2 = [1,2]но [1] + [2] = [1,[2]]. То, что вы предлагаете, это противоречивое поведение. Вероятно, поэтому Python не позволяет вам добавлять один элемент таким способом.
mpen

Что ж, в статически типизированном языке, таком как C #, вы можете сказать, какой тип элементов списка, будь то список списков или список элементов, так что вы можете использовать тип, чтобы решить, добавлять ли один элемент, который является списком, или объединять два списка.
Добес Вандермер

22

Чтобы быть как можно более понятным, вы, возможно, захотите пойти со словом CopyAndAddили чем-то подобным.


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

Кстати, я прочитал ваш профиль, затем возраст в порядке и был кратко удивлен тем, сколько вам лет. Вскоре после этого появился здравомыслие.
JaredPar

Первый комментарий: я использую деревья настолько редко, что эта мысль никогда не приходила мне в голову. Это хороший момент.
Майкл Майерс

Повторяю второй комментарий: признаюсь, я сделал это для значка! Я просто не люблю указывать свой возраст. (Я на самом деле моложе вас, но я могу играть в капризный старожил довольно хорошо, если мне нужно. И я не единственный, чей возраст указан как 89.)
Майкл Майерс

Аргумент об неизменных деревьях - сильный аргумент. Таким образом, EquivalentReferenceWithAdded (x) будет бороться с этим аргументом, но звучит глупо, и его трудно вывести.
TheBlastOne

21

Я бы назвал это Extend () или, может быть, ExtendWith (), если вы хотите по-настоящему многословно.

Расширение означает добавление чего-либо к чему-то другому без изменения. Я думаю, что это очень актуальная терминология в C #, поскольку она похожа на концепцию методов расширения - они «добавляют» новый метод в класс, не «касаясь» самого класса.

В противном случае, если вы действительно хотите подчеркнуть, что вы вообще не изменяете исходный объект, использование какого-либо префикса, такого как Get, выглядит для меня неизбежным.


1
Тем не менее, подразумевается что-то делать с базовым объектом.
хаос

18

Добавлен (), Добавлен ()

Мне нравится использовать прошедшее время для операций над неизменными объектами. Он передает идею, что вы не меняете исходный объект, и его легко узнать, когда вы его видите.

Кроме того, поскольку имена изменяющихся методов часто являются глаголами настоящего времени, это относится к большинству случаев, требующих неизменного имени метода, с которыми вы сталкиваетесь. Например, в неизменяемом стеке есть методы «push» и «popped».


1
Python также использует это соглашение. Например, встроенные функции reversed () и sorted ().
Джо

18

Мне нравится предложение mmyers CopyAndAdd . В соответствии с темой «мутации», возможно, вы могли бы пойти с Bud (бесполое размножение), Grow , Replicate или Evolve ? знак равно

РЕДАКТИРОВАТЬ: продолжить с моей генетической темой, как насчет Procreate , подразумевая, что создан новый объект, который основан на предыдущем, но с добавлением чего-то нового.


14

Это, вероятно, растяжка, но в Ruby есть общепринятая нотация для различия: 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())
);

@ Джордао: Потому что этот вид композиции приводит к гораздо более простой форме инициализации. Зачем иметь две отдельные переменные, когда я хочу только одну? Точно так же я не хочу создавать изменяемую копию - я хочу, чтобы все было неизменным во всем, поскольку это приводит к коду, который легче рассуждать, IMO.
Джон Скит

Все это все еще более громоздко, чем «плюс» и т. Д. Спасибо за идеи, связанные с мутацией, но я определенно предпочитаю подход «держать его неизменным».
Джон Скит

Возможно, тогда всегда будут неверные интерпретации реальной семантики операции. Если вы следуете по маршруту спецификации объекта, мутации не происходит (по крайней мере, внешне), объект только указывает, как будет выглядеть новый неизменный объект. То, что у вас есть, это операция, которая переходит от одного неизменного объекта к другому, и поскольку она называется Copy, нет места для недоразумений.
Jordão

Похоже, единственными именами, которые вам подойдут, являются составные имена, такие как CopyAndAppend, CopyAndAdd и т. Д.
Jordão

1
На самом деле я все больше увлекаюсь этим подходом (со всеми изменениями) как API для неизменяемых коллекций. Однако я бы сказал, что объединение этого подхода с вспомогательными методами для спецификаций по умолчанию, таких как Concat, предлагает лучшее из обоих миров.
конопля

11

Несколько случайных мыслей:

  • ImmutableAdd ()
  • Append ()
  • Конструктор ImmutableList <T> (ImmutableList <T> originalList, T newItem)

1
+1 для НеизменныйДобавить; не увлекается Append (слишком похоже на StringBuilder.Append, который мутирует), а версия конструктора - это проблема с точки зрения сцепления.
Джон Скит

10

DateTime в C # использует Add. Так почему бы не использовать одно и то же имя? Пока пользователи вашего класса понимают, что класс неизменен.


Я бы сказал, что DateTime.Add, как известно, сбивает с толку людей ... но я согласен, что это показывает приоритет.
Джон Скит

1
Точно так же, как методы изменения строки сбивают с толку новых разработчиков. Но достаточно скоро все узнают, что «строки неизменны»
Tundey

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 за союз. Я, однако, заимствую это непосредственно из теории множеств. :-)
Кристоффер Летт

Разве SQL не получает большую часть своей терминологии из теории множеств?
Джейсон Д

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

6

Видимо, я первый человек из Obj-C / Cocoa, который ответил на этот вопрос.

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

Я думаю, что «Добавить» или «Плюс» звучит хорошо. Название самого списка должно быть достаточно, чтобы передать неизменность списка.


Это не список, это набор тестов.
Цтеннер

5

Возможно, есть некоторые слова, которые больше меня помнят, когда я делаю копию и добавляю к ней что-то, а не мутируем экземпляр (например, «Конкатенация»). Но я думаю, что иметь некоторую симметрию для этих слов для других действий было бы хорошо иметь. Я не знаю подобного слова для «Удалить», которое я думаю такого же типа, как «Конкатенация». «Плюс» звучит немного странно для меня. Я не ожидал бы, что это будет использоваться в нечисловом контексте. Но это может также исходить из моего неанглийского фона.

Может быть, я бы использовал эту схему

AddToCopy
RemoveFromCopy
InsertIntoCopy

У них есть свои проблемы, хотя, когда я думаю об этом. Можно подумать, что они что-то удаляют или что-то добавляют к данному аргументу. Не уверен в этом вообще. Думаю, эти слова тоже не очень хороши в цепочке. Слишком многословно, чтобы напечатать.

Может быть, я бы просто использовал простой «Добавить» и друзей тоже. Мне нравится, как это используется в математике

Add 1 to 2 and you get 3

Ну, конечно, 2 остается 2, и вы получите новый номер. Речь идет о двух числах, а не о списке и элементе, но я думаю, что у него есть некоторая аналогия. На мой взгляд, addэто не обязательно означает, что вы что-то мутируете. Я, конечно, понимаю вашу мысль, что наличие одинокого оператора, содержащего только « addа» и не использующего возвращенный новый объект, не выглядит ошибочным. Но теперь я тоже некоторое время думал об этой идее использования другого имени, кроме «добавить», но я просто не могу придумать другое имя, не заставив меня думать: «Хм, мне нужно было бы взглянуть на документацию, чтобы узнать, что речь идет о «потому что его имя отличается от того, что я ожидал бы назвать« добавить ». Просто какая-то странная мысль об этом из litb, не уверен, что это имеет смысл вообще :)


Но копия не всегда необходима в неизменной коллекции. Возьмите бинарное дерево, например. Добавление нового корня не требует копирования, просто новое значение, где одним из листьев является старое дерево
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

Я бы выбрал «Добавить», потому что вижу преимущество лучшего имени, но проблема состоит в том, чтобы найти разные имена для любой другой неизменной операции, которая может сделать класс совершенно незнакомым, если это имеет смысл.


Да, я понимаю вашу точку зрения. Я думаю, что я все еще предпочитаю Плюс, но это стоит учитывать.
Джон Скит

Спасибо Джон. Я с нетерпением жду возможности использовать ваш фреймворк. Я только что прочитал об этом, и это выглядит очень хорошо. Еще раз спасибо.
Джоан Венге
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.