Извините за вафельный заголовок - если бы я мог придумать краткое название, мне не пришлось бы задавать вопрос.
Предположим, у меня есть неизменный тип списка. У него есть операция, 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>
:)