什么是不可变集合上的一个非变异的“添加”方法的最好的名字?

不好意思的是,如果我能拿出一个简洁的标题,我不会问这个问题。

假设我有一个不可变的列表types。 它有一个操作Foo(x) ,它返回一个带有指定参数的新的不可变列表作为最后一个额外的元素。 所以要build立一个值为“你好”,“不可变”,“世界”的string列表,你可以这样写:

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

(这是C#代码,如果你觉得这个语言很重要,我最感兴趣的是C#的build议,这不是一个基本的语言问题,但是这个语言的习惯用法可能很重要。

重要的是现有的列表不会Foo修改,所以empty.Count仍然会返回0。

另一种(更习惯的)达到最终结果的方式是:

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

我的问题是: Foo最好的名字什么?

编辑3 :正如我后来透露,types的名称可能实际上不是ImmutableList<T> ,这使得位置清晰。 想象一下,它是TestSuite ,它是不可变的,因为它是整个框架的一部分是不可变的…

(编辑结束3)

我到目前为止的选项:

  • Add :在.NET中通用,但意味着原始列表的变化
  • Cons :我认为这是function语言中的普通名字,但对那些没有这种语言经验的人来说毫无意义
  • Plus :迄今为止我的最爱,这并不意味着我的变化 。 显然这也是在Haskell中使用的,但是期望稍有不同(Haskell程序员可能期望它将两个列表一起添加,而不是向另一个列表添加单个值)。
  • With :一致的一些其他不变的约定,但不具有相同的“增加”它IMO。
  • And :不是很具描述性。
  • 运营商超负荷+:我真的不喜欢这么多; 我一般认为运营商只适用于较低层次的types。 我愿意被说服!

我正在使用的标准是:

  • 给方法调用的结果留下正确的印象(即它是带有额外元素的原始列表)
  • 使其尽可能清楚,它不会改变现有的列表
  • 如上面第二个例子所示,链接在一起听起来是合理的

如果我没有把自己弄清楚,请询问更多细节。

编辑1:这是我喜欢PlusAdd推理。 考虑这两行代码:

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

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

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

各种各样的答案是有效的:“与添加去。这是什么DateTime做的,和StringReplace方法等,不使不变性明显。” 我同意 – 这里有优先权。 但是,我已经看到很多人调用DateTime.AddString.Replace期望突变 。 有大量的新闻组问题(如果我四处挖掘,可能是SO),回答是“你忽略了String.Replace的返回值;string是不可变的,一个新的string被返回”。

现在,我应该揭示一个微妙的问题 – types可能实际上不是一个不可变的列表,而是一个不同的不可变types。 具体来说,我正在制定一个基准testing框架,您可以将testing添加到套件中,并创build一个新套件。 可能显而易见的是:

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

理想情况下,我希望我的用户不必被告知testing套件是不可变的。 我希望他们陷入成功之坑。 这可能是不可能的,但我想尝试。

我只通过谈论一个不可变的列表types来过度简化原始问题,对此表示歉意。 不是所有的集合都像ImmutableList<T> :)一样具有自描述性

在这样的情况下,我通常和Concat一起去。 这通常意味着我正在创build一个新的对象。

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

我会和Cons一起去,原因很简单:它意味着你想要的东西。

  1. 我非常喜欢说我的意思,特别是在源代码中。 一个新手只需要查一下Cons的定义,然后再读取和使用那一千次。 我发现,从长远来看,即使前期成本稍高一点,使系统更简单也更好。

  2. 事实上,对于没有FP体验的人来说是“毫无意义的”,这实际上是一个很大的优势。 正如你所指出的那样,你发现的所有其他的词已经有了一些意义,而这个意思要么略有不同,要么含糊不清。 一个新的概念应该有一个新的词(或在这种情况下,一个旧的)。 我宁愿有人不得不查找缺点的定义,而不是错误地假设他知道添加。

  3. 从function语言借用的其他操作往往保持原来的名字,没有明显的灾难。 我从来没有看到任何推动提出“地图”和“减less”的同义词,这对非FPers更为熟悉,我也没有看到这样做的任何好处。

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

其实我喜欢,尤其是在地道的方式。 我特别喜欢它,如果你有一个空列表的静态只读属性,也许使构造函数是私人的,所以你总是不得不从空列表生成。

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

每当我遇到命名的阻塞时,我都会触动互联网。

thesaurus.com返回这个“添加”:

定义:毗连,增加; 做进一步的评论

同义词:附加,附加,前缀,追加,补充,加强,提高,build立,充电,继续,提示,图中,肉出,加热,徒步,徒步,挂钩,挂钩包括,顶起来,爵士起来,连接在一起,垫,parlay,搭载,插入,倒在上面,回复,跑起来,说再说一次,打上,雪球,汤,加快,秒杀,补充,变甜,粘性,标记

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

我个人喜欢。()。 如果我正在使用这个对象,在阅读完文档或者代码注释之后,它会清楚它是干什么的,而且在源代码中它可以正常读取。

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

或者,你添加“沿”与.. .. 🙂

 object.AlongWith("this new item"); 

我最终用Add来为BclExtras中的所有不可变集合。 原因是这是一个容易预测的名字。 我并不担心人们对添加一个变异的添加有疑惑,因为这个types的名字是以Immutable为前缀的。

有一段时间我考虑了Cons和其他function风格的名字。 最后我打了折扣,因为他们不是很知名。 当然,function程序员会理解,但他们不是大多数用户。

其他名称:你提到:

  • 另外:我很想/洗这个。 对我来说,这并没有把它和Add做区别开来
  • 与:将导致问题与VB(双关语意)
  • 运营商超载:可发现性将是一个问题

我考虑的选项:

  • Concat:string是不可变的,使用这个。 不幸的是,它只是非常好的添加到最后
  • CopyAdd:复制什么? 来源,名单?
  • AddToNewList:也许是一个很好的列表。 但是如何收集,堆栈,队列等…

不幸的是,这似乎并不是真的

  1. 绝对是一个不可变的操作
  2. 对大多数用户可以理解
  3. 用不到4个字表示

当您考虑List以外的集合时,它会变得更奇怪。 以Stack为例。 即使是第一年的程序员也可以告诉你,Stacks有一个Push / Pop对方法。 如果你创build一个ImmutableStack并给它一个完全不同的名字,我们称它为Foo / Fop,你刚刚为他们添加了更多的工作来使用你的集合。

编辑:对加号编辑的响应

我知道你在哪里与加号。 我认为一个更强大的情况实际上是减去删除。 如果我看到下面的话,我当然会想知道程序员在想什么

 list.Minus(obj); 

加/减号或新配对的最大问题是感觉过度杀伤。 集合本身已经有一个明显的名字,不可变的前缀。 为什么要进一步添加词汇,其目的是添加与Immutable前缀相同的区别。

我可以看到通话网站的参数。 从单一expression的angular度来看它更加清晰。 但在整个function的情况下,似乎没有必要。

编辑2

同意人们肯定已经被String.Concat和DateTime.Add混淆了。 我看到几个非常聪明的程序员遇到了这个问题。

不过我认为ImmutableList是一个不同的论点。 没有什么关于String或DateTime将它build立为程序员不可变的。 你必须简单地知道它是不可变的通过其他来源。 所以这个混乱并不意外。

ImmutableList没有这个问题,因为这个名字定义了它的行为。 你可能会争辩说,人们不知道什么是不可变的,我认为这也是有效的。 我大概在大学二年级后才知道这一点。 但是,无论您select什么名称而不是添加,您都有同样的问题。

编辑3:像TestSuite这样的types是不可变的,但不包含这个词?

我认为这使得你不应该发明新的方法名称。 也就是说,显然是为了促进并行操作而使types不可变。 如果您专注于更改集合方法的名称,则下一步将是您使用的每个types上的变异方法名称,这些名称是不可变的。

我认为这将是一个更有价值的努力,而不是集中在使可识别的types不可变。 这样你就可以解决这个问题,而不用重新思考每一个变异方法模式。

现在你怎么能把TestSuite识别为不可变的? 在今天的环境中,我认为有几种方法

  1. 前缀与Immutable:ImmutableTestSuite
  2. 添加一个描述Immutablitiy级别的属性。 这当然是不容易发现的
  3. 没有其他的。

我的猜测/希望是开发工具将开始通过简单地通过视觉(不同的颜色,更强的字体等)识别不可变types来帮助解决这个问题。 但我认为这是答案,虽然改变了所有的方法名称。

我认为这可能是超负荷运营商可以接受的罕见情况之一。 在math术语中,我们知道+不会把某些东西附加到别的东西的末尾。 它总是将两个值组合在一起,并返回一个新的结果值。

例如,当你说的时候,这很直观

 x = 2 + 2; 

x的结果值是4,而不是22。

同样的,

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

应该清楚每个variables将要持有的东西。 应该清楚的是list2在最后一行没有改变 ,而是list3被赋予了将“word”附加到list2

否则,我只需要命名Plus()函数。

为了尽可能清楚,你可能想要与CopyAndAdd ,或类似的东西。

如果你觉得真的很冗长,我会把它叫做Extend()或者ExtendWith()

扩展意味着添加某些东西而不改变它。 我认为这是C#中非常相关的术语,因为这与扩展方法的概念很相似 – 他们在没有“触及”类本身的情况下“添加”一个新的方法。

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

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

编辑:继续我的遗传主题,如何Procreate ,意味着一个新的对象是基于前一个,但有一些新的东西。

添加(),附加()

我喜欢用过去式来操作不可变的对象。 它expression了你不改变原始对象的想法,当你看到它时很容易辨认。

而且,因为变异方法名称通常是现在动词,所以它适用于大部分不可变方法名称的情况。 例如,一个不可变的堆栈具有“推送”和“popup”的方法。

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

Join似乎是适当的

也许混淆源于一个事实,即你需要两个操作。 为什么不把它们分开? 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操作需要一个委托,它接收一个可变列表,以便它可以控制复制结果。 它可以做的不仅仅是附加一个元素,比如删除元素或者sorting列表。 它也可以在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); } 

现在用户不可能误解,他们自然会陷入成功之坑

又一个更新:

如果你仍然不喜欢可变列表提到,即使现在已经包含它,你可以devise一个规范对象,它将指定脚本 ,复制操作将如何转换其列表。 用法是一样的:

 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支持的function,而不是IList的全部function。

对于链接使用,你可以创build一个合理的构造函数(当然不会使用链接):

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

一些随意的想法:

  • ImmutableAdd()
  • 附加()
  • ImmutableList <T>(ImmutableList <T> originalList,T newItem)构造函数

C#中的DateTime使用Add。 那么为什么不使用相同的名称呢? 只要你的类的用户理解这个类是不可改变的。

我认为你很难expression的关键是不准确的,所以可能是一些带有生成词的东西,比如CopyWith()或者InstancePlus()。

我不认为英语语言会让你用一种明白无误的方式暗示“不变”,而使用与“Add”相同的动词。 “加”几乎是这样,但人们仍然可以犯这个错误。

要阻止用户将对象误认为是可变的,唯一的方法是通过对象本身的名称或方法的名称来明确指定对象(如使用诸如“GetCopyWith”之类的冗长选项或“CopyAndAdd”)。

所以就随你最喜欢的“Plus”去吧。

首先,一个有趣的出发点: http : //en.wikipedia.org/wiki/Naming_conventions_(programming) …特别是,请查看底部的“另请参阅”链接。

我赞成Plus或And,实际上是一样的。

Plus和And都是基于math的词源。 因此,两者都意味着math运算; 同时产生一个expression式,这个expression式可以自然地expression为expression式,这个expression式可以分解成一个值,这个值与具有返回值的方法相符 And承载额外的逻辑内涵,但是这两个词直观地适用于列表。 Add暗指在对象上执行的操作,这与方法的不可变语义相冲突。

两者都很短,鉴于手术的原始性,这一点尤为重要。 简单,经常执行的操作应该使用较短的名称。

expression不变的语义是我喜欢通过上下文来做的事情。 也就是说,我宁愿暗示这整个代码块有一个function的感觉; 假定一切都是不变的。 但是,这可能只是我。 我更喜欢不变性是规则。 如果这样做了,它在同一个地方做了很多, 可变性是例外。

Chain()或Attach()怎么样?

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

其他一些可能性:

拼接()

接枝()

合生()

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

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

这不会赢得任何代码高尔夫游戏。

How about mate , mateWith , or coitus , for those who abide. In terms of reproducing mammals are generally considered immutable.

Going to throw Union out there too. Borrowed from SQL.

I think "Add" or "Plus" sounds fine. The name of the list itself should be enough to convey the list's immutability.

Maybe there are some words which remember me more of making a copy and add stuff to that instead of mutating the instance (like "Concatenate"). But i think having some symmetry for those words for other actions would be good to have too. I don't know of a similar word for "Remove" that i think of the same kind like "Concatenate". "Plus" sounds little strange to me. I wouldn't expect it being used in a non-numerical context. But that could aswell come from my non-english background.

Maybe i would use this scheme

 AddToCopy RemoveFromCopy InsertIntoCopy 

These have their own problems though, when i think about it. One could think they remove something or add something to an argument given. Not sure about it at all. Those words do not play nice in chaining either, i think. Too wordy to type.

Maybe i would just use plain "Add" and friends too. I like how it is used in math

 Add 1 to 2 and you get 3 

Well, certainly, a 2 remains a 2 and you get a new number. This is about two numbers and not about a list and an element, but i think it has some analogy. In my opinion, add does not necessarily mean you mutate something. I certainly see your point that having a lonely statement containing just an add and not using the returned new object does not look buggy. But I've now also thought some time about that idea of using another name than "add" but i just can't come up with another name, without making me think "hmm, i would need to look at the documentation to know what it is about" because its name differs from what I would expect to be called "add". Just some weird thought about this from litb, not sure it makes sense at all 🙂

Looking at http://thesaurus.reference.com/browse/add and http://thesaurus.reference.com/browse/plus I found gain and affix but I'm not sure how much they imply non-mutation.

I think that Plus() and Minus() or, alternatively, Including() , Excluding() are reasonable at implying immutable behavior.

However, no naming choice will ever make it perfectly clear to everyone, so I personally believe that a good xml doc comment would go a very long way here. VS throws these right in your face when you write code in the IDE – they're hard to ignore.

Append – because, note that names of the System.String methods suggest that they mutate the instance, but they don't.

Or I quite like AfterAppending :

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

list.CopyWith(element)

As does Smalltalk 🙂

And also list.copyWithout(element) that removes all occurrences of an element, which is most useful when used as list.copyWithout(null) to remove unset elements.

I would go for Add, because I can see the benefit of a better name, but the problem would be to find different names for every other immutable operation which might make the class quite unfamiliar if that makes sense.