对不起,我的标题太含糊了——如果我能想出一个简洁的标题,我就不用问这个问题了。

假设我有一个不可变的列表类型。它有一个操作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改变,所以是空的。Count仍然返回0。

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

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

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

编辑3:正如我稍后所揭示的,类型的名称实际上可能不是ImmutableList<T>,这使得位置很清楚。相反,想象它是TestSuite,它是不可变的,因为它所在的整个框架是不可变的……

(编辑3结束)

到目前为止,我想到的选项是:

Add: common in .NET, but implies mutation of the original list Cons: I believe this is the normal name in functional languages, but meaningless to those without experience in such languages Plus: my favourite so far, it doesn't imply mutation to me. Apparently this is also used in Haskell but with slightly different expectations (a Haskell programmer might expect it to add two lists together rather than adding a single value to the other list). With: consistent with some other immutable conventions, but doesn't have quite the same "additionness" to it IMO. And: not very descriptive. Operator overload for + : I really don't like this much; I generally think operators should only be applied to lower level types. I'm willing to be persuaded though!

我选择的标准是:

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

如果我说得不够清楚,请再问我一些细节。

编辑1:以下是我更喜欢Plus而不是Add的理由。考虑以下两行代码:

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

在我看来(这是我个人的观点),后者显然是有问题的——它就像写“x + 5;”作为一个单独的语句。第一行看起来是可以的,直到您记得它是不可变的。事实上,加号操作符本身不改变操作数的方式是我最喜欢加号的另一个原因。没有操作符重载的麻烦,它仍然具有相同的含义,其中包括(对我来说)不改变操作数(在本例中是方法目标)。

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

各种各样的回答都很有效:“使用Add。这就是DateTime所做的,而String有Replace方法等,这些方法不会使不可变性变得明显。”我同意,这里有优先权。然而,我见过很多人称之为DateTime。添加或字符串。替换并期待突变。有大量的新闻组问题(如果我仔细研究的话,可能会有这样的问题),这些问题的答案是“您忽略了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>:)那样具有自描述性。


当前回答

list.copyAndAppend(elt)

听起来怎么样?)

其他回答

This seems to come down to finding a word that expresses that the object is not modified. Also, that it is cloned and the element passed as a parameter is added to the end of the cloned list. Standard names like add and clone are never going to cover it. Perhaps clone_and_append which is also rather ambiguous, since the append part might imply that the parameter is appended to the original list. So it should probably be something like clone_and_append_to_clone or better yet append_to_clone, although this one does not really imply that the clone is going to be returned by this method, but rather that the clone already exists as part of the origina list.

因此,更多地考虑寻找一个不意味着对原始列表进行修改的名称,并建议创建一个新列表,考虑以下内容:

Offshoot -- var list1 = list.Offshoot("tail") - in the strictest sense, offshoot refers here to the new element and not the entire new list. Another apparent disadvantage is that it is not an action, the more correct name being list.CreateOffshoot. However, I find it gives a clear indication of the fact that the new list will contain the original list and that the new element will come at the end of the list. Spawn -- var list1 = list.Spawn("tail") - similar to the previous. The advantage is that it is an action, but there is a weaker implication that the new list will contain the original list. BranchOff -- var list1 = list.BranchOff("tail") - an action that suggests the original list will be cloned. One potential ambiguity is that it is not very clear how the parameter element will be used.

游戏开始得很晚,但是《冰雪奇缘》怎么样。在WPF中,使用Freeze和IsFrozen来测试对象是否可变是有优先级的。当然,这有点扭曲了意义,因为通常Freeze()是一种使当前对象不可变的方法,但如果它有一个参数,您可以看到您得到的是不可变的东西。

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

基本上:

这是一个词 其内涵围绕着不变性展开。 WPF中“相似”语法的优先级。

这可能有点夸张,但在Ruby中有一个常用的符号来区分:添加不会改变;添加!变异。如果这是您的项目中普遍存在的问题,您也可以这样做(不一定使用非字母字符,而是始终使用符号来指示突变/非突变方法)。

首先,一个有趣的起点: http://en.wikipedia.org/wiki/Naming_conventions_(编程)……特别是,查看底部的“See Also”链接。

我支持正数或正数,实际上是相等的。

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

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

我更喜欢通过上下文来表达不可变的语义。也就是说,我宁愿简单地暗示这整个代码块具有功能性;假设一切都是不可变的。不过,可能只有我是这样。我宁愿把不变作为准则;如果有人做过,那就是在同一个地方做过很多次;可变性是个例外。

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