对于华丽的标题感到抱歉 - 如果我能想出一个简洁的标题,我就不用问这个问题了.
假设我有一个不可变的列表类型.它有一个操作Foo(x)
,它返回一个带有指定参数的新的不可变列表作为最后的额外元素.因此,要建立一个值为"Hello","immutable","world"的字符串列表,您可以编写:
var empty = new ImmutableList();
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().Foo("Hello")
.Foo("immutable")
.Foo("word");
我的问题是:Foo最好的名字是什么?
编辑3:正如我稍后透露的那样,该类型的名称可能实际上并不存在ImmutableList
,这使得该位置清晰.想象一下,它是TestSuite
并且它是不可变的,因为它所属的整个框架是不可变的......
(编辑完3)
到目前为止我提出的选项:
Add
:常见于.NET,但意味着原始列表的变异
Cons
:我相信这是函数式语言中的正常名称,但对于没有这些语言经验的人来说毫无意义
Plus
:我最喜欢的,它并不意味着我的变异.显然,这也用在Haskell中,但期望略有不同(Haskell程序员可能希望它将两个列表一起添加而不是将一个值添加到另一个列表中).
With
:与其他一些不可变的约定一致,但它与IMO没有完全相同的"附加性".
And
:不是很具描述性.
+的运算符重载:我真的不喜欢这么多; 我通常认为运算符只应用于较低级别的类型.我很乐意被说服!
我用来选择的标准是:
给出方法调用结果的正确印象(即它是带有额外元素的原始列表)
尽可能清楚地表明它不会改变现有列表
在链接在一起时听起来很合理,如上面的第二个例子
如果我不够清楚,请询问更多细节......
编辑1:这里是我的喜欢推理Plus
来Add
.考虑以下两行代码:
list.Add(foo);
list.Plus(foo);
在我看来(这是个人的事情),后者显然是错误的 - 就像写"x + 5;" 作为一个声明本身.第一行看起来没问题,直到你记得它是不可变的.实际上,plus运算符本身不会改变其操作数的方式Plus
是我最喜欢的另一个原因.如果没有操作符重载的轻微瑕疵,它仍然会给出相同的内涵,包括(对我来说)不改变操作数(或者在这种情况下是方法目标).
编辑2:不喜欢的原因添加.
各种答案都是有效的:"Go with Add.这就是做什么DateTime
,并且String
有Replace
方法等不会使不变性变得明显." 我同意 - 这里有优先权.然而,我见过很多人打电话DateTime.Add
或String.Replace
和期望突变.有大量的新闻组问题(如果我四处寻找可能是SO的问题),这些问题的回答是"你忽略了返回值String.Replace
;字符串是不可变的,返回一个新的字符串."
现在,我要透露一个微妙的问题-类型可能不是实际上是不可变列表,但不同类型的不可变的.特别是,我正在开发一个基准测试框架,您可以在其中向套件中添加测试,并创建一个新套件.可能很明显:
var list = new ImmutableList();
list.Add("foo");
是不会完成任何事情,但它成为很多,当你将其更改为迷雾:
var suite = new TestSuite();
suite.Add(x => x.Length);
看起来应该没问题.鉴于此,对我来说,错误更明确:
var suite = new TestSuite();
suite.Plus(x => x.Length);
那只是乞求:
var suite = new TestSuite().Plus(x => x.Length);
理想情况下,我希望我的用户不必被告知测试套件是不可变的.我希望他们陷入成功之中.这可能是不可能的,但我想尝试一下.
我只是通过谈论一个不可变的列表类型而过度简化原始问题而道歉.并非所有的集合都像ImmutableList
:) 一样自我描述
在这样的情况下,我通常会去Concat
.这通常意味着我正在创建一个新对象.
var p = listA.Concat(listB); var k = listA.Concat(item);
我会选择Cons,原因很简单:这意味着你想要它.
我非常喜欢说出我的意思,特别是在源代码中.一个新手必须只查看一次Cons的定义,然后阅读并使用它一千次.我发现,从长远来看,使用能够使普通案例更容易的系统更好,即使前期成本稍微高一些.
事实上,对于没有FP经验的人来说,这将是"毫无意义",这实际上是一个很大的优势.正如你所指出的那样,你发现的所有其他词语都有一些含义,而且这个含义要么略有不同,要么含糊不清.一个新概念应该有一个新词(或者在这种情况下,旧词).我宁愿有人必须查找Cons的定义,而不是假设他不知道Add有什么用.
借用功能语言的其他操作通常保留其原始名称,没有明显的灾难.我还没有看到任何关于"地图"和"减少"的同义词的推动,这听起来对于非FP的人来说更为熟悉,我也没有看到这样做的任何好处.
(完全披露:我是Lisp程序员,所以我已经知道Cons的意思了.)
其实我喜欢And
,特别是在惯用的方式.我特别喜欢它,如果你有一个静态readonly属性为空列表,并可能使构造函数私有所以你总是必须从空列表构建.
var list = ImmutableList.Empty.And("Hello") .And("Immutable") .And("Word");
每当我在一个有命名的果酱时,我都会打起来.
thesaurus.com为"add"返回:
定义: adjoin,增加; 进一步评论
同义词: affix,附件,ante,append,augment,up up,boost,build up,charge up,continue,cue in,figure in,fullh out,heat up,hike,hike up,hitch on,hook on,hook up用,包括,杰克,爵士,加入,垫,parlay,背驮式,插入,倒,回复,跑起来,再说,拍打,雪球,汤,加快,穗,加紧,补充,甜,粘,标签
我喜欢的声音Adjoin
,或更简单Join
.这就是你在做什么,对吧?该方法也适用于加入其他ImmutableList<>
人的.
我个人喜欢.With().如果我正在使用该对象,在阅读文档或代码注释后,它会清楚它的作用,并且它在源代码中读取正常.
object.With("My new item as well");
或者,你添加"沿".. :)
object.AlongWith("this new item");
我最终使用Add来获取BclExtras中的所有不可变集合.原因是它是一个容易预测的名称.我并不担心人们会因添加变异添加而混淆Add,因为类型的名称前缀为Immutable.
有一段时间我考虑了Cons和其他功能样式名称.最后我给他们打了折扣,因为他们并不是那么出名.当然功能程序员会理解,但他们不是大多数用户.
其他名称:你提到过:
另外:我很希望/洗这个.对我来说,这并没有将它区分为非变异操作,而不是Add
使用:会导致VB问题(双关语)
运营商重载:可发现性是一个问题
我考虑的选项:
Concat:String是不可变的并且使用它.不幸的是,添加到最后只是非常好
CopyAdd:复制什么?来源,清单?
AddToNewList:对于List来说也许是一个好的.但是收集,堆栈,队列等等呢......
不幸的是,似乎没有一个词
绝对是一个不可变的操作
可以为大多数用户所理解
可用不到4个字表示
当你考虑List之外的集合时,它会变得更奇怪.以Stack为例.即使是第一年的程序员也可以告诉你Stacks有一对Push/Pop方法.如果你创建一个ImmutableStack并给它一个完全不同的名字,让我们称之为Foo/Fop,你刚刚为它们添加了更多的工作来使用你的集合.
编辑:对Plus Edit的响应
我知道你要去Plus的地方.我认为一个更强的案例实际上是Minus删除.如果我看到以下内容,我当然会想知道程序员在想什么
list.Minus(obj);
我对Plus/Minus或新配对的最大问题是感觉有点矫枉过正.集合本身已经有一个与众不同的名称,即不可变的前缀.为什么要进一步添加词汇表,其意图是添加与Immutable前缀相同的区别.
我可以看到调用站点参数.从单个表达的角度来看,它更清晰.但在整个功能的背景下,似乎没有必要.
编辑2
同意人们肯定被String.Concat和DateTime.Add搞糊涂了.我见过几个非常聪明的程序员遇到了这个问题.
但是我认为ImmutableList是一个不同的参数.String或DateTime没有任何东西将它建立为程序员不可变.你必须通过其他来源简单地知道它是不可变的.所以混乱并不出乎意料.
ImmutableList没有这个问题,因为名称定义了它的行为.你可能会说人们不知道Immutable是什么,我认为这也是有效的.直到大学二年级,我当然不知道.但是,无论您选择何种名称而不是添加,您都会遇到同样的问题.
编辑3:像TestSuite这样的类型是不可变的,但不包含这个词?
我认为这可以让你认识到你不应该发明新的方法名称.即因为有明显的驱动器使类型不可变以便于并行操作.如果您专注于更改集合的方法名称,则下一步将是您使用的每个类型的变异方法名称,这些名称是不可变的.
我认为将重点放在将类型识别为不可变的方面是一种更有价值的努力.这样你就可以解决问题,而无需重新思考每个变异方法模式.
现在,您如何将TestSuite识别为不可变?在今天的环境中,我认为有几种方法
使用Immutable:ImmutableTestSuite的前缀
添加描述Immutablitiy级别的属性.这当然不太容易被发现
没什么别的.
我的猜测/希望是开发工具将开始帮助解决这个问题,只需通过视觉(不同的颜色,更强的字体等等)轻松识别不可变类型.但我认为这是改变所有方法名称的答案.
我认为这可能是极少数情况下可以接受+
操作员超载的情况之一.在数学术语中,我们知道+
不会在其他东西的末尾附加某些东西.它总是将两个值组合在一起并返回一个新的结果值.
例如,当你说时,直观显而易见
x = 2 + 2;
x的结果值是4,而不是22.
同样的,
var empty = new ImmutableList(); var list1 = empty + "Hello"; var list2 = list1 + "immutable"; var list3 = list2 + "word";
应该明确每个变量将要保留的内容.应该清楚的list2
是,在最后一行没有改变,而是list3
分配了附加"单词"的结果list2
.
否则,我只会将函数命名为Plus().
为了尽可能清楚,你可能想要使用wordier CopyAndAdd
或类似的东西.
如果你真的很冗长,我会把它叫做Extend()或者说ExtendWith().
扩展意味着在不改变的情况下向其他内容添加内容.我认为这是C#中非常相关的术语,因为它类似于扩展方法的概念 - 它们在没有"触及"类本身的情况下向类添加"新方法".
否则,如果你真的想强调你根本不修改原始对象,那么使用像Get这样的前缀看起来对我来说是不可避免的.
我喜欢mmyers建议的CopyAndAdd.为了与"变异"主题保持一致,也许你可以选择Bud(无性繁殖),成长,复制或进化?=)
编辑:继续我的遗传主题,如何生成Procreate,暗示一个新的对象是基于前一个,但添加了一些新的东西.
添加(),附加()
我喜欢使用过去时对不可变对象的操作.它表达了你不会改变原始物体的想法,并且当你看到它时很容易识别.
此外,由于变异方法名称通常是紧张动词,因此它适用于您遇到的大多数不可变方法名称所需的案例.例如,不可变堆栈具有"推"和"弹出"的方法.
这可能是一个延伸,但在Ruby中有一个常用的符号表示区分:add
不变异; add!
变异.如果这是您项目中的普遍问题,您也可以这样做(不一定使用非字母字符,但始终使用表示法来表示变异/非变异方法).
Join
似乎合适.
也许混淆源于你想要两个操作合二为一的事实.为什么不将它们分开?DSL风格:
var list = new ImmutableList("Hello"); var list2 = list.Copy().With("World!");
Copy
会返回一个中间对象,这是原始列表的可变副本.With
将返回一个新的不可变列表.
更新:
但是,拥有一个中间的,可变的集合并不是一个好方法.中间对象应该包含在Copy
操作中:
var list1 = new ImmutableList("Hello"); var list2 = list1.Copy(list => list.Add("World!"));
现在,该Copy
操作接受一个委托,它接收一个可变列表,以便它可以控制复制结果.除了附加元素之外,它还可以做很多事情,比如删除元素或对列表进行排序.它也可以在ImmutableList
构造函数中用于组装初始列表而不需要中间不可变列表.
public ImmutableListCopy(Action > mutate) { if (mutate == null) return this; var list = new List (this); mutate(list); return new ImmutableList (list); }
现在用户不可能误解,他们自然会陷入成功的困境.
又一次更新:
如果您仍然不喜欢可变列表提及,即使现在已经包含它,您也可以设计一个规范对象,它将指定或编写复制操作如何转换其列表的脚本.用法是一样的:
var list1 = new ImmutableList("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("Hello", "immutable", "World");
或者在另一个构造函数中使用相同的委托:
var list = new ImmutableList(rules => rules .Append("Hello") .Append("immutable") .Append("World") );
这假定该rules.Append
方法返回this
.
这是你最新的例子:
var suite = new TestSuite(x => x.Length); var otherSuite = suite.Copy(rules => rules .Append(x => Int32.Parse(x)) .Append(x => x.GetHashCode()) );
一些随意的想法:
ImmutableAdd()
附加()
ImmutableList
C#中的DateTime使用Add.那么为什么不使用相同的名字呢?只要您的类的用户理解该类是不可变的.
我认为你想要表达的关键是难以表达的东西,所以也许是带有生成词的东西,比如CopyWith()或InstancePlus().
在使用与"添加"相同的动词时,我不认为英语会让你以明白无误的方式暗示不变性."加"几乎可以做到,但人们仍然可以犯这个错误.
您要防止用户将对象误认为可变的唯一方法是通过对象本身的名称或通过方法的名称(如"GetCopyWith"等详细选项)将其显式化. "CopyAndAdd").
所以请选择你最喜欢的"Plus".
首先,一个有趣的起点:http: //en.wikipedia.org/wiki/Naming_conventions_ (programming) ...特别要检查底部的"另请参见"链接.
我赞成Plus或And,实际上同样如此.
Plus和And都是基于数学的词源学.因此,两者都意味着数学运算; 两者都产生一个表达式,该表达式自然地读取为可以解析为值的表达式,该值与具有返回值的方法相符. And
具有额外的逻辑含义,但这两个词直观地适用于列表. Add
意味着对对象执行的操作,该操作与方法的不可变语义冲突.
两者都很短,鉴于操作的原始性,这一点尤为重要.简单,经常执行的操作需要更短的名称.
表达不可变语义是我喜欢通过上下文做的事情.也就是说,我只是简单地暗示整个代码块都具有功能感; 假设一切都是不可改变的.然而,那可能只是我.我更喜欢不变性作为规则; 如果它完成了,它在同一个地方做了很多; 可变性是例外.
Chain()或Attach()怎么样?
我更喜欢Plus(和Minus).它们很容易理解,并直接映射到涉及众所周知的不可变类型(数字)的操作.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"];
不会用这个赢得任何代码高尔夫游戏.
对于那些住在那里的人,mate,mateWith或coitus怎么样?在繁殖方面,哺乳动物通常被认为是不可改变的.
还要把联盟扔出去.借用SQL.
我认为"添加"或"加号"听起来不错.列表本身的名称应该足以传达列表的不变性.
也许有些单词让我更多地记住了制作副本并添加内容而不是改变实例(如"连接").但我认为对于其他行动而言,这些词语具有一定的对称性也会很好.我不知道"删除"的类似词,我认为像"连接"一样."加"对我来说听起来并不奇怪.我不希望它被用在非数字语境中.但这也可能来自我的非英语背景.
也许我会使用这个方案
AddToCopy RemoveFromCopy InsertIntoCopy
当我考虑它时,它们有自己的问题.人们可能会认为他们删除了某些东西或者给出了一些参数.根本不确定.我想,这些话在链接中也不好看.太罗嗦了.
也许我只会使用简单的"添加"和朋友.我喜欢它在数学中的用法
Add 1 to 2 and you get 3
嗯,当然,2仍然是2,你得到一个新的数字.这是关于两个数字而不是关于列表和元素,但我认为它有一些类比.在我看来,add
并不一定意味着你会改变一些东西.我当然认为你的观点是,拥有一个只包含一个add
而不使用返回的新对象的孤独语句看起来并不错.但我现在也想到了一些关于使用另一个名称而不是"添加"的想法,但我只是想不出另一个名字,而不是让我想到"嗯,我需要查看文档来了解什么它是关于"因为它的名字与我期望被称为"添加"的名称不同.只是一些奇怪的想法从litb,不知道它有意义:)
看看http://thesaurus.reference.com/browse/add和http://thesaurus.reference.com/browse/plus我找到了收益和词缀,但我不确定他们有多少暗示非突变.
我认为,Plus()
和Minus()
,或者Including()
,Excluding()
是在合理的暗示一成不变的行为.
但是,没有命名选择会让每个人都清楚,所以我个人认为一个好的xml doc评论会在这里走很长的路.当您在IDE中编写代码时,VS会将这些权利抛到您的脸上 - 它们很难被忽略.