Как лучше всего назвать не мутирующий метод «add» в неизменяемой коллекции? - PullRequest
224 голосов
/ 06 февраля 2009

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

Предположим, у меня есть тип неизменяемого списка. Он имеет операцию 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: не очень описательный.
  • Перегрузка оператора для +: мне действительно не очень нравится; Я вообще думаю, что операторы должны применяться только к типам более низкого уровня. Я готов быть убежденным, хотя!

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

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

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

РЕДАКТИРОВАТЬ 1: Вот мои аргументы в пользу предпочтения от Plus до Add. Рассмотрим эти две строки кода:

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

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

РЕДАКТИРОВАТЬ 2: Причины неприязни Add.

Различные ответы эффективны: «Идите с 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>:)

Ответы [ 74 ]

7 голосов
/ 09 февраля 2010

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

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

Не собираюсь выигрывать любые игры в гольф с кодом.

7 голосов
/ 07 февраля 2009

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

Некоторые другие возможности:

сращивание ()

Прививка ()

обрастать ()

6 голосов
/ 07 февраля 2009

Как насчет mate , mateWith или coitus , для тех, кто пребывает. С точки зрения размножения млекопитающие обычно считаются неизменными.

Собираюсь выбросить Союз там тоже. Заимствовано из SQL.

5 голосов
/ 07 февраля 2009

Глядя на http://thesaurus.reference.com/browse/add и http://thesaurus.reference.com/browse/plus Я нашел усиление и аффикс , но я не уверен, насколько они подразумевают немутацию.

5 голосов
/ 06 февраля 2009

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

5 голосов
/ 07 февраля 2009

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

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

AddToCopy
RemoveFromCopy
InsertIntoCopy

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

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

Add 1 to 2 and you get 3

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

5 голосов
/ 12 июня 2009

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

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

4 голосов
/ 06 февраля 2009

Append - потому что обратите внимание, что имена методов System.String предполагают, что они видоизменяют экземпляр, но не делают.

Или мне очень нравится AfterAppending:

void test()
{
  Bar bar = new Bar();
  List list = bar.AfterAppending("foo");
}
4 голосов
/ 28 февраля 2009

list.CopyWith(element)

Как и Smalltalk:)

А также list.copyWithout(element), который удаляет все вхождения элемента, что наиболее полезно при использовании в качестве list.copyWithout(null) для удаления неустановленных элементов.

3 голосов
/ 17 апреля 2009

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

...