234

很抱歉标题有点啰嗦——如果我能想出一个简洁的标题,我就不必问这个问题了。

假设我有一个不可变的列表类型。它有一个操作,该操作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);

在我看来(这个人的事情),后者显然是有问题的——就像写“x + 5;”一样。作为自己的声明。第一行看起来没问题,直到您记住它是不可变的。Plus事实上,加号运算符本身不会改变其操作数的方式是我最喜欢的另一个原因。如果没有运算符重载的轻微恶心,它仍然给出相同的含义,其中包括(对我而言)不改变操作数(或在这种情况下的方法目标)。

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

各种答案都是有效的:“使用 Add。这就是DateTime它的作用,并且String具有Replace不会使不变性明显的方法等。” 我同意 - 这里有优先级。但是,我看到很多人打电话DateTime.AddorString.Replace期待 mutation。有很多新闻组问题(如果我仔细研究的话,可能还有一些问题),这些问题的答案是“你忽略了 ; 的返回值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>并非所有收藏都像:)那样具有自我描述性

4

75 回答 75

132

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

var p = listA.Concat(listB);
var k = listA.Concat(item);
于 2009-02-06T21:22:32.657 回答
119

我会选择 Cons,原因很简单:这正是你想要的。

  1. 我非常喜欢准确地说出我的意思,尤其是在源代码中。新手只需查找一次 Cons 的定义,然后阅读并使用一千次。我发现,从长远来看,使用使常见情况变得更容易的系统会更好,即使前期成本会更高一些。

  2. 对于没有 FP 经验的人来说,它“毫无意义”这一事实实际上是一个很大的优势。正如您所指出的,您发现的所有其他词都已经具有某种含义,并且该含义略有不同或模棱两可。一个新概念应该有一个新词(或者在这种情况下,一个旧词)。我宁愿有人必须查找 Cons 的定义,而不是错误地假设他知道 Add 做什么。

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

(完全披露:我是一名 Lisp 程序员,所以我已经知道 Cons 的含义。)

于 2009-02-06T21:03:37.403 回答
59

其实我喜欢And,尤其是惯用的方式。如果你有一个空列表的静态只读属性,我会特别喜欢它,并且可能将构造函数设为私有,这样你总是必须从空列表构建。

var list = ImmutableList<string>.Empty.And("Hello")
                                      .And("Immutable")
                                      .And("Word");
于 2009-02-06T20:12:41.750 回答
52

每当我陷入命名法的困境时,我都会上网。

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

定义:邻接,增加;进一步发表评论

同义词:词缀、附件、前注、附加、增加、加强、提升、建立、充电、继续、提示、图进来、充实、加热、远足、远足、搭便车、挂钩、挂钩与,包括,自升,爵士乐,加入,垫,parlay,背驮式,插入,倒上,回复,跑起来,说得更远,拍打,滚雪球,加汤,加速,穗,加紧,补充、增甜、粘贴、标记

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

于 2009-02-06T20:57:56.013 回答
48

就个人而言,我喜欢 .With()。如果我正在使用该对象,在阅读文档或代码注释后,它会清楚它的作用,并且它在源代码中读取正常。

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

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

object.AlongWith("this new item");
于 2009-02-06T21:02:38.483 回答
35

我最终为BclExtras中的所有不可变集合添加了 Add 。原因是它是一个容易预测的名字。我不太担心人们会将 Add 与变异 add 混淆,因为类型的名称以 Immutable 为前缀。

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

其他名称:您提到:

  • 另外:我希望/洗这个。对我来说,这并不比 Add 区分它是一个非变异操作
  • With:会导致 VB 出现问题(双关语)
  • 运算符重载:可发现性将是一个问题

我考虑的选项:

  • Concat:字符串是不可变的并使用它。不幸的是,它只适合添加到结尾
  • CopyAdd:复制什么?来源,清单?
  • AddToNewList:对于 List 来说可能是一个不错的选择。但是集合、堆栈、队列等呢?

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

  1. 绝对是不可变的操作
  2. 为广大用户所理解
  3. 用少于 4 个字表示

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

编辑:对加编辑的回应

我知道您将与 Plus 一起去哪里。我认为一个更强有力的案例实际上是减去删除。如果我看到以下内容,我肯定会想知道程序员到底在想什么

list.Minus(obj);

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

我可以看到调用站点参数。从单个表达式的角度来看,它更清楚。但在整个函数的上下文中,这似乎是不必要的。

编辑 2

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

但是我认为 ImmutableList 是一个不同的论点。没有任何关于 String 或 DateTime 将其确定为对程序员不可变的内容。您必须简单地知道它通过其他来源是不可变的。所以混乱并不意外。

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

编辑 3:像 TestSuite 这样不可变但不包含单词的类型呢?

我认为这使您不应该发明新方法名称的想法成为现实。即因为显然存在使类型不可变以促进并行操作的驱动力。如果您专注于更改集合的方法名称,下一步将是您使用的每种不可变类型上的变异方法名称。

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

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

  1. 不可变前缀:ImmutableTestSuite
  2. 添加一个描述 Immutablitiy 级别的属性。这肯定不太容易被发现
  3. 别的不多。

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

于 2009-02-06T19:54:03.007 回答
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

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

于 2009-02-06T21:27:51.023 回答
22

为了尽可能清楚,您可能想要使用 wordierCopyAndAdd或类似的东西。

于 2009-02-06T19:55:03.860 回答
21

如果您觉得非常冗长,我会称它为Extend()ExtendWith() 。

扩展意味着将某些内容添加到其他内容而不更改它。我认为这是 C# 中非常相关的术语,因为这类似于扩展方法的概念——它们“添加”一个新方法到一个类而不“接触”类本身。

否则,如果您真的想强调根本不修改原始对象,那么使用 Get- 之类的前缀对我来说似乎是不可避免的。

于 2009-02-06T20:01:37.857 回答
18

添加(),附加()

我喜欢使用过去时对不可变对象进行操作。它传达了您没有更改原始对象的想法,并且在您看到它时很容易识别。

此外,由于可变方法名称通常是现在时动词,因此它适用于您遇到的大多数需要不可变方法名称的情况。例如,不可变堆栈具有“推送”和“弹出”方法。

于 2009-02-06T21:34:15.207 回答
18

我喜欢 mmyers 的CopyAndAdd建议。为了与“突变”主题保持一致,也许您可​​以选择Bud(无性繁殖)、GrowReplicateEvolve?=)

编辑:继续我的遗传主题, Procreate怎么样,这意味着一个新对象是基于前一个对象制作的,但添加了一些新的东西。

于 2009-02-06T20:03:12.800 回答
14

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

于 2009-02-06T22:48:28.737 回答
13

Join似乎合适。

于 2009-02-06T22:42:17.330 回答
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())
);
于 2010-02-07T05:31:24.743 回答
11

一些随意的想法:

  • 不可变添加()
  • 附加()
  • ImmutableList<T>(ImmutableList<T> originalList, T newItem) 构造函数
于 2009-02-06T19:56:44.420 回答
10

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

于 2009-02-06T19:55:32.083 回答
9

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

我赞成 Plus 或 And,实际上同样有效。

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

两者都很短,考虑到操作的原始性,这一点尤其重要。简单、频繁执行的操作应该使用更短的名称。

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

于 2009-02-06T21:30:17.647 回答
9

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

防止用户将对象误认为是可变对象的唯一方法是通过对象本身的名称或方法的名称(如“GetCopyWith”或“复制并添加”)。

因此,请选择您最喜欢的“Plus”。

于 2009-02-06T20:36:08.707 回答
9

我认为你试图表达的关键是非排列,所以可能是包含生成词的东西,比如 CopyWith() 或 InstancePlus()。

于 2009-02-06T20:07:11.903 回答
8

Chain() 或 Attach() 怎么样?

于 2009-02-06T21:48:32.680 回答
7

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

其他一些可能性:

拼接()

接枝()

混凝土()

于 2009-02-07T00:18:56.963 回答
6

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

也要把联盟扔出去。从 SQL 借来的。

于 2009-02-06T22:24:15.667 回答
6

Apparently I'm the first Obj-C/Cocoa person to answer this question.

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

Not going to win any code golf games with this.

于 2010-02-09T14:11:48.773 回答
5

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

也许我会使用这个方案

AddToCopy
RemoveFromCopy
InsertIntoCopy

但是,当我想到它时,这些都有自己的问题。人们可能会认为他们删除了某些东西或在给定的论点中添加了一些东西。完全不确定。我认为,这些词在链接方面也不好。写得太啰嗦了。

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

Add 1 to 2 and you get 3

好吧,当然,2 仍然是 2,你得到一个新数字。这是关于两个数字而不是关于一个列表和一个元素,但我认为它有一些类比。在我看来,add并不一定意味着你改变了一些东西。我当然明白你的观点,即有一个只包含一个add而不使用返回的新对象的孤独语句看起来并没有问题。但我现在也考虑过使用“add”以外的其他名称的想法,但我就是想不出另一个名称,而不让我想到“嗯,我需要查看文档才能知道什么它是关于”,因为它的名称与我期望的“添加”不同。只是来自 litb 的一些奇怪的想法,不确定它是否有意义:)

于 2009-02-06T21:11:29.573 回答
5

查看http://thesaurus.reference.com/browse/addhttp://thesaurus.reference.com/browse/plus我发现了增益词缀,但我不确定它们在多大程度上暗示了非突变。

于 2009-02-07T14:58:06.707 回答
5

我认为Plus()and Minus()or, 或者,Including()暗示不可变行为Excluding()方面是合理的。

但是,任何命名选择都不会让每个人都非常清楚,所以我个人认为,一个好的 xml 文档注释在这里会有很长的路要走。当您在 IDE 中编写代码时,VS 会将这些直接扔到您面前——它们很难被忽视。

于 2009-06-11T22:25:29.977 回答
5

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

于 2009-02-06T19:57:15.200 回答
4

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

或者我很喜欢AfterAppending

void test()
{
  Bar bar = new Bar();
  List list = bar.AfterAppending("foo");
}
于 2009-02-06T20:02:37.620 回答
4

list.CopyWith(element)

和 Smalltalk 一样 :)

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

于 2009-02-28T16:01:40.320 回答
3

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.

于 2009-04-17T18:39:15.590 回答
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# 在这里有无类函数。或者至少类似于 Java 的静态导入工具。

操作员可以是+

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

但我宁愿能够使用其他的东西,比如<<,::.,这在 C# 中是不可能的。

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

于 2010-06-04T19:43:01.017 回答
3

我个人喜欢unite(),因为当你将物体结合在一起时,你仍然保留了它们的个性,但它们的结合是一个单独的新实体。Union与建议的相似,但已经在集合论中得到了很好的定义,并且unite更加冗长,并告诉我遵循该方法我有一个新的实体。我知道它迟到了,但他们在列表中找不到建议。加上这个词让我想起了过去和团结人们去打仗的日子。呵呵

于 2010-09-30T13:14:36.597 回答
2

2条建议:

“免费”功能:

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

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

Foo f = new Foo(whatever);
Foo fPlusSomething = new Foo(f, something);
于 2009-02-06T22:18:45.367 回答
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");
于 2011-05-17T16:42:23.617 回答
2

WithAdded 这个名字读起来很好,恕我直言,比可以读作形容词的 Added 更好。

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

或者更详细的版本:

var list2 = list1.WithAddedElement("immutable");
于 2011-05-20T22:54:34.643 回答
2

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

我必须同意这并不意味着该论点被添加到列表的末尾,但我个人属于简洁的可能阵营,所以我赞成list.NewList("word")list.NewListAfterAppend("word")

于 2011-09-21T19:22:29.803 回答
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?
于 2011-06-22T20:34:03.380 回答
1

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

不过,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 并希望智能显示的内容非常接近我的预期。

于 2009-04-04T07:01:35.453 回答
1

我会亲自去AddVoid或相反VoidAdd

于 2011-02-03T22:22:50.257 回答
1

如果你是一个函数式程序员,这有几个名字:

(++)

读作“追加”。或者它可能是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 的列表中。


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

于 2011-05-20T07:02:30.937 回答
1

作为 C++ 程序员和 STL 的粉丝,我提出了add_copy. (这也建议remove_copyreplace_copy等等)

于 2010-02-25T19:35:42.080 回答
1

1)问题的问题分析
摘要可以是:
从一个不可变的......得到一个新的不可变但与原来的不同..
在这个当前的问题上下文中:
从一个不可变的列表得到一个新的不可变列表,有一个新的不同元素加到底。

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

2) 建议分析
第一个概念:Immutable 给出一个类似的不可变,
>>“copy” 动词在“content”中表达保守但较少为它定义约束(immutable)
>>“clone” 动词在“content”中表达保守但也为其定义的约束。
>>“twin” 动词与clone类似,但在软件中不常见,但短小精悍。

第二个概念:结果给出了与原始对象不同的东西
>>“添加”表示一个动作,以区分原始对象和新对象,但根据定义,我们不执行(变异)不可变对象。
>表达动词结果将在不干扰原始宾语的情况下增加的事实......“副词”方法更“不可变”友好
>>“with”表达了“动词”会做更多事情但可能模棱两可的事实它将做更多的事情。也可以表示“动词参数”是“动词”的“更多”

3)答案
与动词“clone”
>> augmentClone
>> growClone
>> extendClone
with “with”
>> cloneWith
>> augmentCloneWith
>> growCloneWith
>> extendCloneWith

带有动词“twin”
>> augmentTwin
>>




>> growTwinWith
>> extendTwinWith

于 2011-08-26T08:47:20.417 回答
1

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

因此,更多地考虑寻找一个不暗示对原始列表进行修改并且还建议创建一个新列表的名称,请考虑以下事项:

  1. 分支——var list1 = list.Offshoot("tail")在最严格的意义上,分支在这里指的是新元素,而不是整个新列表。另一个明显的缺点是它不是一个动作,更正确的名称是list.CreateOffshoot. 但是,我发现它清楚地表明了新列表将包含原始列表并且新元素将出现在列表末尾的事实。
  2. Spawn——var list1 = list.Spawn("tail")前面类似。优点是它是一个动作,但新列表将包含原始列表的含义较弱。
  3. BranchOff -- var list1 = list.BranchOff("tail")建议将克隆原始列表的操作。一个潜在的歧义是参数元素将如何使用不是很清楚。
于 2011-07-01T09:35:07.663 回答
1

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

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

Suffix传达了它的附加性并Copy明确了不变性。随意Suffix用更合乎逻辑的东西替换它实际上是那种测试套件(也许你没有将这些后缀添加到一个大的内部字符串,你可以提供我所知道的测试用例名称/参数)。

于 2011-08-03T00:56:15.213 回答
1

虽然正确命名方法可以减少误用的机会,但如果有某种语言结构告诉编译器:“这个方法只返回一个新对象,应该使用它,否则方法调用毫无意义”,然后编译器可以每当有人在错误的设置中使用该方法时,都会抱怨错误/警告。

如果您同意,我已经填写了一个功能请求,请随时投票。

于 2015-08-28T18:16:27.547 回答
0

比赛很晚了,但是怎么样Freeze。WPF 中有优先使用FreezeIsFrozen测试对象是否可变的优先级。诚然,这稍微歪曲了含义,因为它通常Freeze()是一种使当前对象不可变的方法,但如果它有一个参数,你可以看到你得到的东西是不可变的。

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

基本上:

  1. 这是一个词
  2. 内涵围绕着不变性。
  3. WPF 中“相似”语法的优先级。
于 2009-04-15T21:24:40.860 回答
0

就我个人而言,我会调用该方法Clone并调用参数AdditionalValue,因为这本质上就是它看起来正在做的事情,并且很容易理解,例如

var empty = new ImmutableList<string>(); 
var list1 = empty.Clone("Hello"); 
var list2 = list1.Clone("immutable"); 
var list3 = list2.Clone("word");
于 2010-05-24T10:07:45.130 回答
0

我会选择“CreateNewListWithAdditionalItems”

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

于 2010-11-23T17:02:58.930 回答
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);
于 2009-03-11T15:00:57.813 回答
0

How about "Stick" or "StickTo", it sticks an element on the end.

Or "Attach" or "AttachTo".

于 2009-02-08T14:38:03.873 回答
0

如前所述,您尝试一次做两件事并为此目的进行微优化。如果复制发生在原始集合定义之外,“Add”、“Append”之类的名称只会造成混淆。

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

于 2010-04-24T22:59:22.650 回答
0

.Trail 表示非常强的理解列表没有改变,这个对象在列表的后面,它没有被添加到它。

var list = new ImmutableList<string>().Trail("Hello");
                                      .Trail("immutable");
                                      .Trail("word");
于 2009-02-06T21:09:57.050 回答
0

“添加()”

它返回一个新列表的事实无关紧要,这是签名所揭示的实现细节。该方法完成的主要操作是将新元素“添加”到列表中。它处理或返回的方式或内容不应成为方法名称的一部分。如果一个方法是同步的,那会影响方法名称 -“synchronizedAdd()” ??? - 当然不是。

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

于 2009-02-06T21:14:48.537 回答
0

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

于 2009-02-06T23:44:49.623 回答
0

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

于 2010-02-07T18:29:01.527 回答
0

我会使用构造函数。

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

f1 包含“一”。f2 包含“一”、“二”。f3 包含“一”、“二”、“三”。

于 2009-02-08T15:16:11.520 回答
0

由于这个问题现在基本上是一个词库:How about .Bring(). 如,给我这个清单并带上这个元素?

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

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

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

于 2009-10-08T04:58:29.097 回答
0

I know this is beating a seemingly dead horse, but I think you may be approaching this in an odd way (hence the naming difficulty). When I have an immutable object, I don't often expect that the object will have functions that imply mutability (like Add or AddAll). I know that String & DateTime do this, but even I have fallen victim to forgetting to use the results from DateTime / String functions so I would avoid those pitfalls if possible.

If I were you, I would follow the Builder pattern similar to what Guava uses. See immutable collections in Guava. Basically the concept is that you construct the immutable object with everything it is ever going to contain. If you want to make a new immutable object, you need to use a new builder.

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

You can expand upon the builder to allow a variety of modifications to the test suite (using standard list naming conventions like add / remove if you wish) before the user calls build.

于 2012-01-10T18:48:22.320 回答
0

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

于 2009-02-06T20:34:50.363 回答
0

就我个人而言,如果您追求流畅的风格,我可能会选择 Pad(..),也可以使用 AndWith(..) 的扩展方法

var list = new ImmutableList<string>().Pad("Hello")
                                      .AndWith("immutable")
                                      .AndWith("word");
于 2011-11-16T22:04:51.093 回答
0

借用C,怎么样Concat

于 2011-01-07T18:55:31.043 回答
0

list.copyAndAppend(elt)

听上去怎么样?)

于 2010-03-03T18:25:28.803 回答
0

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

于 2009-02-06T20:00:40.807 回答
0

我会选择简单的 Add()。如果您想表达这确实是一个收集操作,另一种选择是 Append()。

除了显式方法,我仍然建议实现 obverloaded + 操作符。这是一个众所周知的操作。每个人都知道 String 是不可变的,但每个人都使用“+”来构建它的新实例。

于 2009-02-06T20:02:26.077 回答
0

“增强”怎么样?

这是一个与 Add 不同的词,但它是一个接近的同义词。

于 2009-02-06T20:05:53.700 回答
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");

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

于 2009-04-16T02:22:40.690 回答
0

我来晚了,NewWith 怎么样?

于 2009-03-06T10:36:13.780 回答
0

我喜欢 And()。我认为它最不可能产生歧义。我能想到的唯一冲突是逻辑而且,我不认为这是 C# 开发人员的问题,甚至对于 VB,我认为上下文不太可能导致问题,任何问题都会在编译时间。它在英语“Do something to These And That”或“Put These And That in the box”中也很有效。

我认为.With() 是可以的。我担心它可能看起来有点像 linq Where<> 方法,特别是如果有一个 lambda 作为参数。我脑子里的英语也不太清楚,尤其是“用那个对这些做点什么”。

我不喜欢 .Plus()。我无法将它作为 Add 的同义词:plus = plus sign = + = add。

于 2009-02-06T19:55:06.997 回答
0

一个很晚的答案,但我想补充两分:我认为这里的重点可能是动词时态而不是动词本身:

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

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

于 2014-10-08T16:31:32.537 回答
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()));

ETC....

于 2009-06-26T12:43:40.747 回答
0

Augment用(或AugmentWith)方法创建一个包装类怎么样?

于 2009-08-03T11:49:18.133 回答
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");
于 2011-03-03T14:45:21.583 回答
0

对于这种功能,我通常使用第二种形式的动词,Added在这种情况下。

这个约定被 Qt 使用,例如QVector2D::normalized返回一个规范化的向量,同时QVector2D::normalize规范化一个向量。

以同样的方式Added将返回带有新添加项目的对象。

于 2010-11-22T12:52:35.617 回答
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包一部分的集合中看到这一点。

于 2021-01-30T01:33:18.803 回答
0

另一个赞成的观点Plus是新的几乎不可变的Java 时间 APIplus()例如用于添加到Instants.

于 2016-01-25T18:21:49.557 回答