在不可变集合上使用非变异“add”方法的最佳名称是什么?

时间:2009-02-06 19:49:30

标签: language-agnostic naming-conventions list immutability

对于华丽的标题感到抱歉 - 如果我能想出一个简洁的标题,我就不用问这个问题了。

假设我有一个不可变的列表类型。它有一个操作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:到目前为止,我最喜欢的,并不意味着对我的突变。显然这也是used in Haskell,但期望略有不同(Haskell程序员可能希望它将两个列表一起添加,而不是将一个值添加到另一个列表中)。
  • With:与其他一些不可变的约定一致,但与IMO没有完全相同的“附加性”。
  • And:不是很具描述性。
  • +的运算符重载:我真的不喜欢这么多;我通常认为运算符只应用于较低级别的类型。我很乐意被说服!

我用来选择的标准是:

  • 给出方法调用结果的正确印象(即它是带有额外元素的原始列表)
  • 尽可能清楚地表明它不会改变现有列表
  • 在上面第二个例子中链接在一起时听起来很合理

如果我不够清楚自己,请询问更多细节......

编辑1:以下是我更喜欢PlusAdd的理由。请考虑以下两行代码:

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

在我看来(这个 是个人的东西),后者显然是错误的 - 就像写“x + 5;”作为一个声明本身。第一行看起来没问题,直到你记得它是不可变的。事实上,plus运算符本身不会改变其操作数的方式是Plus是我最喜欢的另一个原因。如果没有操作符重载的轻微瑕疵,它仍然会给出相同的内涵,包括(对我来说)不改变操作数(或者在这种情况下是方法目标)。

编辑2:不喜欢的原因添加。

各种答案都是有效的:“Go with Add。这就是DateTime所做的,而StringReplace方法等,这些方法不会使不变性显而易见。”我同意 - 这里有优先权。但是,我看到很多人打电话给DateTime.AddString.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>一样具有自我描述性:)

75 个答案:

答案 0 :(得分:128)

在这种情况下,我通常会选择Concat。这通常意味着我正在创建一个新对象。

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

答案 1 :(得分:119)

我会选择Cons,原因很简单:它意味着你想要它。

  1. 我非常喜欢说出我的意思,特别是在源代码中。一个新手必须只查看一次Cons的定义,然后阅读并使用它一千次。我发现,从长远来看,使用能够使普通案例更容易的系统更好,即使前期成本稍微高一些。

  2. 对于没有FP经验的人来说,它“毫无意义”这一事实实际上是一个很大的优势。正如你所指出的那样,你发现的所有其他词语都有一些含义,而且这个含义要么略有不同,要么含糊不清。一个新概念应该有一个新词(或者在这种情况下,是一个旧词)。我宁愿有人要查看Cons的定义,而不是错误地认为他知道Add的作用。

  3. 从函数式语言中借用的其他操作通常保留其原始名称,没有明显的灾难。我没有看到任何推动提出“地图”和“减少”的同义词,这听起来对非FP人员来说更为熟悉,我也没有看到这样做的任何好处。

  4. (完全披露:我是Lisp程序员,所以我已经知道Cons的意思了。)

答案 2 :(得分:58)

其实我喜欢And,尤其是习惯用法。我特别喜欢它,如果你有一个静态readonly属性为空列表,并可能使构造函数私有所以你总是必须从空列表构建。

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

答案 3 :(得分:51)

每当我遇到命名的果酱时,我就会打起网。

thesaurus.com为“add”返回此内容:

  

定义: adjoin,increase;使   进一步评论

     

同义词:词缀,   附件,赌注,追加,增加,牛肉   起来,提升,积累,充电,   继续,提示,数字,肉体   出去,加热,徒步旅行,徒步旅行,搭便车,   挂钩,挂钩,包括,杰克   up,jazz up,join together,pad,   parlay,搭载,插入,倒入它   打开,回复,跑起来,进一步说,打耳光   上,雪球,汤,加快,   穗,加强,补充,变甜,   粘贴,标记

我喜欢Adjoin的声音,或更简单地Join。这就是你在做什么,对吧?该方法也适用于加入其他ImmutableList<>

答案 4 :(得分:48)

我个人喜欢.With()。如果我正在使用该对象,在阅读完文档或代码注释之后,它会很清楚它的作用,并且它在源代码中可以正常显示。

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

或者,你用它添加“沿”.. :)

object.AlongWith("this new item");

答案 5 :(得分:33)

我最终在BclExtras中使用Add来获取所有不可变集合。原因是它是一个容易预测的名称。我并不担心人们会因为类型的名称前缀为Immutable而混淆添加变异添加。

有一段时间我考虑过Cons和其他功能样式名称。最后我给他们打了折扣,因为他们并不是那么出名。当然,功能程序员会理解,但他们不是大多数用户。

其他名称:你提到过:

  • 另外:我很想/洗这个。对我来说,这并没有将其区分为非变异操作,而不是添加
  • 使用:会导致VB问题(双关语)
  • 运营商重载:可发现性是一个问题

我考虑的选项:

  • Concat:String是不可变的并且使用它。不幸的是,添加到最后只是非常好
  • CopyAdd:复制什么?来源,清单?
  • AddToNewList:也许是List的好词。但是收藏,堆叠,队列等等呢......

不幸的是,似乎没有一个单词

  1. 绝对是一个不可变的操作
  2. 了解大多数用户
  3. 只能用不到4个字表示
  4. 当你考虑List以外的集合时会更奇怪。以Stack为例。即使是第一年的程序员也可以告诉你Stacks有一对Push / Pop方法。如果你创建一个ImmutableStack并给它一个完全不同的名字,让我们称之为Foo / Fop,你刚刚为它们添加了更多的工作来使用你的集合。

    修改:对Plus编辑的响应

    我知道你要去Plus的地方。我认为一个更强的案例实际上是Minus删除。如果我看到以下内容,我当然会想知道程序员在想什么

    list.Minus(obj);
    

    我对Plus / Minus或新配对的最大问题是感觉有点矫枉过正。集合本身已经有一个与众不同的名称,即不可变的前缀。为什么要进一步添加词汇表,其意图是添加与不可变前缀相同的区别。

    我可以看到调用网站参数。从单个表达的角度来看,它更清晰。但在整个功能的背景下,这似乎是不必要的。

    修改2

    同意人们肯定被String.Concat和DateTime.Add搞糊涂了。我见过几个非常聪明的程序员遇到了这个问题。

    但是我认为ImmutableList是一个不同的参数。 String或DateTime没有任何东西将它建立为程序员不可变。您必须通过其他来源知道它是不可变的。所以混乱并不出乎意料。

    ImmutableList没有这个问题,因为名称定义了它的行为。你可能会说人们不知道Immutable是什么,我认为这也是有效的。直到大学二年级,我当然不知道。但是,无论您选择何种名称而不是添加,您都会遇到同样的问题。

    编辑3: TestSuite等类型是不可变的,但不包含单词?

    我认为这可以让你想到你不应该发明新的方法名称。即因为有明显的驱动器使类型不可变以便于并行操作。如果您专注于更改集合的方法名称,则下一步将是您使用的每个类型的变异方法名称,这些名称是不可变的。

    我认为将重点放在将类型识别为不可变的方面将是一项更有价值的工作。这样你就可以解决问题,而无需重新思考每个变异方法模式。

    现在,您如何将TestSuite识别为不可变?在今天的环境中,我认为有几种方法

    1. 带有Immutable的前缀:ImmutableTestSuite
    2. 添加描述Immutablitiy等级的属性。这当然不太容易被发现
    3. 别无其他。
    4. 我的猜测/希望是开发工具将通过简单地通过视觉(不同的颜色,更强的字体等等)轻松识别不可变类型来开始帮助解决这个问题。但我认为这是改变所有方法名称的答案。

答案 6 :(得分: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分配了将“word”附加到list2的结果。< / p>

否则,我只会将函数命名为Plus()。

答案 7 :(得分:22)

为了尽可能清楚,你可能想要使用更多的CopyAndAdd或类似的东西。

答案 8 :(得分:21)

如果您觉得非常详细,我会称之为 Extend()或者 ExtendWith()

扩展意味着在不改变的情况下向其他内容添加内容。我认为这是C#中非常相关的术语,因为它类似于扩展方法的概念 - 它们在没有“触及”类本身的情况下向类添加“新方法”。

否则,如果你真的想强调你根本不修改原始对象,那么使用像Get这样的前缀看起来对我来说是不可避免的。

答案 9 :(得分:18)

我喜欢mmyers建议 CopyAndAdd 。为了与“突变”主题保持一致,也许你可以选择 Bud (无性繁殖),成长复制进化? =)

编辑:继续我的遗传主题,生育如何,暗示一个新的对象是基于前一个,但添加了新的东西。

答案 10 :(得分:16)

添加(),附加()

我喜欢使用过去时对不可变对象的操作。它表达了你没有改变原始物体的想法,当你看到它时很容易识别。

此外,由于变异方法名称通常是紧张动词,因此它适用于您遇到的大多数不可变方法名称所需的案例。例如,不可变堆栈的方法是“推”和“弹出”。

答案 11 :(得分:14)

这可能是一个延伸,但在Ruby中有一个常用的符号表示:add不会发生变异; add!变异。如果这是您项目中的普遍问题,您也可以这样做(不一定使用非字母字符,但始终使用表示法来表示变异/非变异方法)。

答案 12 :(得分: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())
);

答案 13 :(得分:13)

Join似乎合适。

答案 14 :(得分:11)

一些随意的想法:

  • ImmutableAdd()
  • 追加()
  • ImmutableList&lt; T&gt;(ImmutableList&lt; T&gt; originalList,T newItem)构造函数

答案 15 :(得分:10)

C#中的DateTime使用Add。那么为什么不使用相同的名字呢?只要您的类的用户理解该类是不可变的。

答案 16 :(得分:9)

首先,一个有趣的起点: http://en.wikipedia.org/wiki/Naming_conventions_(programming) ...特别要检查底部的“另请参见”链接。

我赞成Plus或And,实际上同样如此。

Plus和And都是基于数学的词源学。因此,两者都意味着数学运算;两者都产生一个表达式,该表达式自然地读取为可以解析为值的表达式,该值与具有返回值的方法相符。 And具有额外的逻辑含义,但这两个词直观地应用于列表。 Add表示对对象执行的操作,该操作与方法的不可变语义冲突。

两者都很短,考虑到操作的原始性,这一点尤为重要。简单,经常执行的操作需要更短的名称。

表达不可变语义是我喜欢通过上下文做的事情。也就是说,我只是简单地暗示整个代码块都具有功能感;假设一切都是不可改变的。然而,那可能只是我。我更喜欢不变性作为规则;如果它完成了,它在同一个地方做了很多; 可变性是个例外。

答案 17 :(得分:9)

在使用与“添加”相同的动词时,我认为英语不会让你以明白无误的方式暗示不变性。 “加”几乎可以做到,但人们仍然可以犯这个错误。

你要阻止你的用户将对象误认为是可变的东西的唯一方法是通过对象本身的名称或通过方法的名称使其明确(如同详细的选项,如“ GetCopyWith“或”CopyAndAdd“)。

所以请选择你最喜欢的,“加号。”

答案 18 :(得分:9)

我认为你努力想要表达的关键是无法表达,所以也许是带有生成词的东西,比如CopyWith()或InstancePlus()。

答案 19 :(得分:8)

Chain()或Attach()怎么样?

答案 20 :(得分:7)

显然我是第一个回答这个问题的Obj-C / Cocoa人。

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

不会用这个赢得任何代码高尔夫球比赛。

答案 21 :(得分:7)

我更喜欢Plus(和减号)。它们很容易理解,并直接映射到涉及众所周知的不可变类型(数字)的操作。 2 + 2不会改变2的值,它会返回一个新的,同样不可变的值。

其他一些可能性:

剪接()

接枝()

共生()

答案 22 :(得分:6)

对于那些遵守的人来说,配偶 mateWith coitus 怎么样?在繁殖方面,哺乳动物通常被认为是不可改变的。

也要把联盟扔出去。借用SQL。

答案 23 :(得分:5)

查看http://thesaurus.reference.com/browse/addhttp://thesaurus.reference.com/browse/plus我发现获胜加贴,但我不确定他们有多少暗示非突变。< / p>

答案 24 :(得分:5)

也许有些单词更让我记住了制作副本并添加内容而不是改变实例(如“连接”)。但我认为对于其他行动而言,这些词语具有一定的对称性也会很好。我不知道“删除”的类似词,我认为像“连接”一样。 “加”对我来说听起来并不奇怪。我不希望它被用在非数字语境中。但这也可能来自我的非英语背景。

也许我会使用这个方案

AddToCopy
RemoveFromCopy
InsertIntoCopy

当我考虑它时,它们有自己的问题。人们可能会认为他们删除了某些东西或者给出了一些参数。根本不确定。我想,这些话在链接中也不好看。太罗嗦了。

也许我只会使用简单的“添加”和朋友。我喜欢它在数学中的用法

Add 1 to 2 and you get 3

嗯,当然,2还是2,你得到一个新号码。这是关于两个数字,而不是关于列表和元素,但我认为它有一些类比。在我看来,add并不一定意味着你会改变某些东西。我当然认为你的观点是,只有add而不使用返回的新对象的孤独语句看起来并不错。但我现在也想到了一些关于使用另一个名称而不是“添加”的想法,但我只是想不出另一个名字,而不是让我想到“嗯,我需要查看文档来了解什么它是关于“因为它的名字与我期望被称为”添加“的名称不同。从litb看起来只是一些奇怪的想法,不确定它是否有意义:))

答案 25 :(得分:5)

我认为“添加”或“加号”听起来不错。列表本身的名称应该足以传达列表的不变性。

答案 26 :(得分:5)

我认为Plus()Minus()或者Including()Excluding()暗示不可变行为时是合理的。

然而,没有命名选择会让每个人都清楚,所以我个人认为一个好的xml doc评论会在这里走很长的路。

,当您在IDE中编写代码时,VS会将这些权利抛到您的脸上

答案 27 :(得分:4)

list.CopyWith(element)

和Smalltalk一样:)

还有list.copyWithout(element)删除所有出现的元素,这在用作list.copyWithout(null)用于删除未设置元素时最有用。

答案 28 :(得分:4)

Append - 因为,请注意System.String方法的名称表明它们会改变实例,但它们不会。

或者我非常喜欢AfterAppending

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

答案 29 :(得分:3)

也许静态方法或运算符(静态)最好。它将承担远离实例的责任,并且用户将立即知道该操作不属于任何实例。特别重要的是不要使用扩展方法,因为它们与使用时的实例方法的相似性会使目的失败。

静态方法可以称为Join

public static class ListOperations {
  public static ImmutableList<T> Join<T>(ImmutableList<T> list, T tail) {
    // ...
  }
  public static ImmutableList<T> Join<T>(T head, ImmutableList<T> list) {
    // ...
  }
  public static ImmutableList<T> Join<T>(ImmutableList<T> list1, ImmutableList<T> list2) {
    // ...
  }
  // substitutes chaining:
  public static ImmutableList<T> Join<T>(ImmutableList<T> list, params T[] tail) {
    // ...
  }
}

// ....

var list = new ImmutableList<string>("Hello");
var list2 = ListOperations.Join(list, "immutable"); // inferred type parameter
var list3 = ListOperations.Join(list2, "world!");

但我更喜欢C#在这里class-free functions。或者至少像Java的静态导入工具。

运营商可以是+

var list = new ImmutableList<string>("Hello");
var list2 = list + "immutable";
var list3 = list2 + "world!";

但我宁愿能够使用其他内容,例如<<::.,这些在C#中是不可能的。

此外,静态成员看起来更实用,我认为更适合这种不可变的视图。

答案 30 :(得分:3)

我会选择Add,因为我可以看到一个更好名字的好处,但问题是为每个其他不可变操作找到不同的名称,这可能会使该类非常陌生,如果这是有道理的。

答案 31 :(得分:3)

我个人喜欢unite(),因为当您联合对象时,您仍然保留其个性,但它们的联合是一个单独的新实体。 Union与建议的相似,但已经在集合理论中得到了很好的定义,而unite更加强大,并告诉我,按照这种方法我有一个新的实用性。我知道它已经很晚了但是他找不到列表中的建议。再加上这个词让我想起了老人们团结起来参加战争的日子。呵呵

答案 32 :(得分:2)

2条建议:

“免费”功能:

Foo f = new Foo(whatever);
Foo fPlusSomething = Foo.Concat(f, something);

构造函数重载(在某种程度上,是“自由函数”主题的变体):

Foo f = new Foo(whatever);
Foo fPlusSomething = new Foo(f, something);

答案 33 :(得分:2)

我会选择list.NewList("word")因为它描述了你在做什么(创建一个新列表)。

我必须同意这并不意味着这个论点被添加到列表的末尾,但我个人认为属于 succinct-if-possible camp ,所以我赞成{{ 1}}超过list.NewList("word")

答案 34 :(得分:2)

我参加派对有点晚了,但我没有看到一个答案,表明根本就没有这样做!让它保持不变。当你把它放入一个循环时,你放的任何方法都会被滥用,最终会发生这种情况。相反,我建议改为使用构建器。

MyImmutableBuilder builder = new MyImmutableBuilder(someImmutable);
MyImmutable modifiedImmultable = builder.add(element1).add(element2).build();

现在在ImmutableList的情况下,你的构建器实际上只是一个List,很可能是。

我想这一切归结为......你真的想要一个简单的方法来为你的不可变集合添加一个元素吗?如果它是常见的,你可能不希望使用不可变对象(你可以随时在你想要发送对象的快照时调用build() ......如果它不是一个常见的事情,然后有一个建设者作为一个要求,这不会是一个重大的障碍,特别是如果记录这是你想要建立它们的方式。

@supercat - 考虑您描述的以下场景:

Stack a = someImmutableStackOfSize(10);
Stack b = a.popAndCopy(); // size 9
Stack c = a.popAndCopy(); // also size 9
// a b and c have the same backing list
Stack d = b.pushAndCopy("node1");
Stack e = c.pushAndCopy("node2");
// because d and e had the same backing list, how will it 
// know that d's last element is node1, but e's last
// element is node2?

答案 35 :(得分:2)

名字WithAdded读得很好,恕我直言比添加更好,可以作为形容词阅读。

var list2 = list1.WithAdded("immutable");

或者稍微冗长的版本:

var list2 = list1.WithAddedElement("immutable");

答案 36 :(得分:2)

cloneWith怎么样?

<强>理由:
 1.对于建议的单个单词名称,在检查文档之前,我不确定他们做了什么  2.对于目前建议的化合物名称,我更喜欢cloneWith。我确切地知道我用这个方法名称得到了什么,它相对简洁,很容易记住,它只是“感觉”正确:)  3.在大多数编程工具中使用现代代码完成,更长的名称比以前更容易使用。

虽然很多时候简洁性会增加清晰度,但如果你必须选择......,则要清晰简明!

在行动中:

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

答案 37 :(得分:1)

copyWithSuffix:将是与Objective-C不可变字符串复制方法stringByAppendingString:类似的自定义方法名称。

var suite = new TestSuite<string>();
suite = suite.CopyWithSuffix("Str1")
             .CopyWithSuffix("Str2")
             .CopyWithSuffix("Str3");

Suffix传达了它的附加信息,Copy使不变性变得清晰。随意替换Suffix更实际的测试套件(可能你没有将这些内容添加到一个大的内部字符串,你可能会为所有我提供测试用例名称/参数)知道)。

答案 38 :(得分:1)

这似乎归结为找到一个表示该对象未被修改的单词。此外,克隆它并将作为参数传递的元素添加到克隆列表的末尾。像addclone这样的标准名称永远不会涵盖它。也许clone_and_append也是相当模糊的,因为append部分可能暗示参数被附加到原始列表。所以它可能应该是clone_and_append_to_clone或更好append_to_clone,尽管这并不意味着克隆将由此方法返回,而是克隆已经作为一部分存在原始名单。

因此,在寻找一个不暗示对原始列表进行修改的名称并且还建议创建新列表时,请考虑以下内容:

  1. 分支 - var list1 = list.Offshoot("tail") - 在最严格的意义上, offshoot 在这里指的是新元素,而不是整个新列表。另一个明显的缺点是它不是一个动作,更正确的名称是list.CreateOffshoot。但是,我发现它清楚地表明新列表将包含原始列表,并且新元素将出现在列表的末尾。
  2. Spawn - var list1 = list.Spawn("tail") - 与之前类似。优点是它是一个动作,但新的列表将包含原始列表的含义较弱。
  3. BranchOff - var list1 = list.BranchOff("tail") - 建议克隆原始列表的操作。一个潜在的模糊性是,不清楚如何使用参数元素。

答案 39 :(得分:1)

任何暗示将返回相同类型的对象的名称都可以使用。 Plus是一个很好的名称,好像你加上两个对象,你希望返回结果。

另外,听起来不像在这个实例中使用的正确名称,因为你正在测试套件中加上测试。

GetWith()听起来像是我的选择。或者GetTypeWith()其中type显然是你使用的类型。例如:

var list = new ImmutableList<String>();
var list2 = list.GetWith("First");
var list3 = list2.GetWith("Second");

// OR

var list2 = list.GetListWith("First");

Get意味着您正在获取已包含的列表,而With意味着您需要另一个对象。 CopyWith()也符合这个标准。

我在GetWith看到的直接问题是它不易猜测。开发人员想要添加套件,而不是获取当前套件。我马上输入.Add并希望intellisence显示出与我期望的非常接近的东西。

答案 40 :(得分:1)

如果您是一名功能性程序员,则会有一些名称:

(++)

发音为“append”。或者它可以是concat,具体取决于您的类型:

-- join two things into one thing:
append :: a -> a -> a    

-- join many things into one thing
concat :: [a] -> a

或者你的意思是(:),AKA cons

(:) :: a -> [a] -> [a]    

如果您将内容加入到列表的前面,snoc如果它已经结束了。

至少在过去的20年里,我们一直在将这些东西列入Haskell-land的名单。


注意,这不是算术(+),因为它是幺半群,而不是环。

答案 41 :(得分:1)

1)问题分析 问题的摘要可以是:
从一个不可改变的...得到一个新的不可变但不同于原来的..
在当前的问题背景下:
从不可变列表得到一个新的不可变列表,最后还有一个新元素的差异。

你能否给出一个有效的“动词”(编程语言中的“方法”),在不使用简单的“添加”动词的情况下以简洁的方式表达动作。

2)提案分析
第一个概念:不变的给出一个类似的不可变的,
&gt;&gt;“复制” 动词在“内容”中表达保护,但对于定义的约束(不可变)则较少 &gt;&gt;“克隆” 动词在“内容”中表达保守,但也表示其定义的约束。
&gt;&gt;“twin” 动词与克隆类似,但在软件中并不常见,但它很短且声音很好。

第二个概念:结果给出了与原来不同的东西 &gt;&gt;“添加”表达操作以区分原始对象和新对象,但根据定义,我们不会执行(mutate)不可变的操作。
&gt;&gt;“加”表示动词结果会在不打扰原始对象的情况下得到扩充...“副词”方法更“不可变”友好
&gt;&gt;“with”与之前一样,它表达了“动词”会做更多事情的事实,但可能会对它将做的事情更加暧昧。也可以表达“动词参数”是“动词”中的“更多”的事实 3)答案
用动词“克隆”
&GT;&GT; augmentClone
&GT;&GT; growClone
&GT;&GT; extendClone
与“与”
&GT;&GT; cloneWith
&GT;&GT; augmentCloneWith
&GT;&GT; growCloneWith
&GT;&GT; extendCloneWith

用动词“twin”
&GT;&GT; augmentTwin
&GT;&GT; growTwin
&GT;&GT; extendTwin
与“与”
&GT;&GT; twinWith
&GT;&GT; augmentTwinWith
&GT;&GT; growTwinWith
&GT;&GT; extendTwinWith

答案 42 :(得分:1)

我个人会使用AddVoidVoidAdd

的其他方式

答案 43 :(得分:1)

作为一名c ++程序员和STL的粉丝,我提出了add_copy。 (这也会建议remove_copyreplace_copy等等)

答案 44 :(得分:1)

虽然正确命名方法可以减少误用的可能性,但是如果有一些语言结构告诉编译器:&#34;这个方法除了返回一个新对象,它应该被使用或者方法调用没有意义& #34;然后,只要有人在错误的设置中使用该方法,编译器就会抱怨错误/警告。

如果你同意的话,我已经填了feature request这样可以自由投票。

答案 45 :(得分:0)

相反/除了名称之外,不可变容器集合是运算符重载的经典案例(就像 int/string/etc 的情况一样)。这里有两个优点:

  • 简洁:l1 = l + o1 + o2 而不是 l1 = l.Add(o1).Add(o2)

  • 使用赋值运算符:l += o 而不是 l = l.Add(o)

使用运算符也使代码不易出错,从可变类型切换到不可变类型时忘记赋值并只写 ie l.Add(o);(具有灾难性的影响)但是只写 l+o; 而没有使用结果真的很突出。

您可以在作为 F 包一部分的集合中看到这一点。

答案 46 :(得分:0)

另一个支持Plus的点是新的大多数不可变Java time API,其中plus()例如用于添加到Instant

答案 47 :(得分:0)

对于这种函数,我通常使用第二种形式的动词{@ 1}}。

此约定由Qt使用,例如QVector2D::normalized返回标准化向量,而Added标准化向量。

以同样的方式QVector2D::normalize将使用新添加的项返回对象。

答案 48 :(得分:0)

我会选择“CreateNewListWithAdditionalItems”

我不介意长名,但是这个名字告诉你它实际上会做什么。如果你使用Add或任何其他改变方法,我也会抛出异常。

答案 49 :(得分:0)

一个非常晚的答案,但我想加上我的两分钱:我认为这里的重点可能是动词本身比动词本身更多:

var output= myList.joinedWith("Element"); //or AddedTo, ConcatenatedTo...

在我看来,分词改变了含义:我们没有向myList添加任何内容,而是返回操作的结果。

答案 50 :(得分:0)

借用C,Concat

怎么样?

答案 51 :(得分:0)

String.Replace等方法的问题在于用户可能会错误地认为存在突变,因为他可以忽略返回值。因此,请使用out参数作为“返回”值。用户不能忽略

public class ImmutableList<T> {
  public ImmutableList(params T[] items) { 
    // ...
  }
  /// <summary>
  /// Creates a new list with the items in this list plus the supplied items.
  /// </summary>
  /// <param name="newList">
  /// The new list created for the operation.
  /// This is also the return value of this method.
  /// </param>
  /// <param name="items">Items to add to the new list.</param>
  /// <returns>The new list.</returns>
  public ImmutableList<T> Add(out ImmutableList<T> newList, params T[] items) {
    // ...
  }
}

用法:

var list = new ImmutableList<string>("Hello", "Immutable");
ImmutableList<string> newList;
list.Add(out newList, "World");

答案 52 :(得分:0)

我知道这打败了一匹看似死马,但我认为你可能会以一种奇怪的方式接近这一点(因此命名困难)。当我有一个不可变对象时,我通常不会期望该对象具有暗示可变性的函数(如Add或AddAll)。我知道String&amp; DateTime执行此操作,但即使我忘记使用DateTime / String函数的结果也是受害者,所以如果可能的话,我会避免这些陷阱。

如果我是你,我会遵循类似于Guava使用的Builder模式。见immutable collections in Guava。基本上,这个概念是你用它将要包含的所有东西构造不可变对象。如果要创建新的不可变对象,则需要使用新的构建器。

var suite = new TestSuite.Builder<string, int>().add(newTest).build();

您可以在构建器上进行扩展,以允许对用户调用构建之前对测试套件进行各种修改(使用标准列表命名约定,如添加/删除)。

答案 53 :(得分:0)

我个人会选择Pad(..),如果你是一个流利的风格,也可以使用AndWith的扩展方法(..)

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

答案 54 :(得分:0)

我到这里有点晚了,NewWith怎么样?

答案 55 :(得分:0)

我喜欢和()。我认为它最不容易出现歧义。我能想到的唯一冲突是有逻辑性的,我不认为这是一个C#开发人员的问题,甚至对于VB我认为上下文使它不太可能导致问题,任何问题都会在编译时间。它也适用于英语“对这些和那些做点什么”或“把这些和那些放在盒子里”。

我认为 .With()可以。我担心的是它看起来有点像linq Where&lt;&gt;方法,特别是如果有一个lambda作为参数。我脑子里的英语也不太清楚,特别是“用那种方式做点什么”。

我不喜欢.Plus()。我无法将其作为Add:plus = plus sign = + = add。

的同义词

答案 56 :(得分:0)

“替换”?它不会添加到列表中,而是用新的列表替换列表。

答案 57 :(得分:0)

我会选择简单的Add()。另一种选择是Append(),如果你想传达这实际上是一个集合操作。

除了显式方法,我还是建议实现obverloaded + operatr。这是一项众所周知的行动。每个人都知道String是不可变的,但每个人都使用'+'来构建它的新实例。

答案 58 :(得分:0)

“增强”怎么样?

这与Add不同,但它是一个紧密的同义词。

答案 59 :(得分:0)

由于类型名称是ImmutableList,因此指定它实际上是不可变的,我认为.Add()很好。但是,如果你对其他东西非常敏感,我可能会使用类似.AddEx()的东西,其中Ex表示扩展,并暗示用户在使用之前应该确定Ex是什么(通过阅读文档)。我也喜欢Plus()和GetCopyWith()

的建议

答案 60 :(得分:0)

.Trail意味着对列表的强烈理解没有改变,这个对象落后于列表,它还没有添加到它。

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

答案 61 :(得分:0)

“add()”

它返回一个新列表的事实并不重要,这是签名显示的实现细节。该方法完成的主要操作是将“添加”新元素添加到列表中。如何或者什么它deos或return不应该是方法名称的一部分。如果同步的方法会影响方法名称 - “synchronizedAdd()”??? - 当然不是。

像String这样遵循will-be-mutator模式的类仍然有非常简单的方法名称 - 没有一个是复合词。

答案 62 :(得分:0)

所以我猜一个名为“ImmutableAdd()”的方法过于简单了?

答案 63 :(得分:0)

“Stick”或“StickTo”怎么样,它会在最后添加一个元素。

或“附加”或“AttachTo”。

答案 64 :(得分:0)

我会使用构造函数。

Foo f1 = new Foo("one");
Foo f2 = new Foo(f1, "two");
Foo f3 = new Foo(f2, "three");

f1包含“one”。 f2包含“一个”,“两个”。 f3包含“一个”,“两个”,“三个”。

答案 65 :(得分:0)

就个人而言,我会调用方法Clone并调用参数AdditionalValue,因为它基本上是出现正在做的事情,并且很容易理解,例如。

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

答案 66 :(得分:0)

我称之为ToInclude

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

惯用(?)

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

适用于您提到的案例。

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

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

答案 67 :(得分:0)

游戏很晚,但Freeze怎么样? WPF中优先使用FreezeIsFrozen来测试对象是否可变。当然,这会稍微扭曲一点意义,因为Freeze()通常意味着使当前对象成为不可变的,但如果它有一个参数,你可以看到你得到了一些不可变的东西。 / p>

var list = new ImmutableList<string>().Freeze("Hello")
                                      .Freeze("Fridgid")
                                      .Freeze("World");

基本上:

  1. 这是一个字
  2. 内涵围绕着不变性。
  3. WPF中对“类似”语法的优先权。

答案 68 :(得分:0)

扩展方法怎么样?在这种情况下,您可以将其称为Join。作为一种扩展方法,用户应该知道它是一种静态方法,因此可能会给它们一点停顿并鼓励它们查看返回值。同时,您具有“实例”方法的可用性。

public static ImmutableList<T> Join(this ImmutableList<T> body, T tail)
{
    // add robust error checking in case either is null...
    return new ImmutableList<T>(body, tail);
}

然后又......

var list = new ImmutableList<string>().Join("Hello")
                                      .Join("Extensible")
                                      .Join("World");

我不太清楚发布多个答案的公认行为,但这是一个有趣的问题,因为我认为命名法是设计中的关键步骤,我的大脑一直在思考这个问题。

答案 69 :(得分:0)

C#-ish伪代码如下:

interface Foo
{
    // Constructors
    Foo();
    Foo(params Foo[] foos);

    // Instance method
    Foo Join(params Foo[] foos);

    // Class method
    static Foo Join(params Foo[] foos);
}    

所以你可以这样称呼:

var f0 = new Foo();
var f1 = new Foo(new Foo(), new Foo(), new Foo());
var f2 = Foo.Join(new Foo(), new Foo(), new Foo());
var f3 = f0.Join(new Foo(), new Foo(), new Foo());
var f4 = new Foo(new Foo(new Foo()), new Foo(), new Foo(new Foo()));

等...

答案 70 :(得分:0)

如何使用Augment(或AugmentWith)方法创建包装类?

答案 71 :(得分:0)

由于这个问题现在基本上是一个词库:.Bring()怎么样。如上所示,给我这个列表并带上这个元素吗?

Foo = List.Bring('short');
          .Bring('longer');
          .Bring('woah');

它不会从舌头上滚下来,但意味着它对我来说。

实际上,AndBring()可能会更好。

答案 72 :(得分:0)

我会使用运算符重载+。原因在于它在Python中的工作方式 - 列表上的.append()会改变列表,而使用另一个列表执行+会创建一个新列表。 +也绝对不暗示突变。我认为这就是你如此喜欢.Plus()的原因,所以如果你不想让运算符重载,那么你可以使用.Plus()

答案 73 :(得分:0)

list.copyAndAppend(ELT)

听起来怎么样?)

答案 74 :(得分:0)

如前所述,您正在尝试同时执行两项操作并仅为此目的进行微观优化。如果复制远离原始集合定义,则“添加”,“附加”等名称只会混淆。

CloneAppend ”是我在这种情况下可能会使用的。有些东西告诉我,我不会在这种情况下。我相信很快您就会发现自己需要其他类似的操作,例如“ CloneFirstN ”或“ CloneRemoveLast ”。很快你就会意识到链接克隆/复制方法,附加/删除你需要的东西要好得多,然后将集合转换回不可变,即使它需要额外的代码行。