首页 文章

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

提问于
浏览
222

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

假设我有一个不可变的列表类型 . 它有一个操作 Foo(x) ,它返回一个新的不可变列表,其中指定的参数作为最后的额外元素 . 因此,要 Build 一个包含值"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");

我的问题是: what's the best name for Foo?

EDIT 3 :正如我稍后透露的那样,该类型的名称实际上可能不是 ImmutableList<T> ,这使得该位置清晰 . 想象一下,它是 TestSuite 并且它是's immutable because the whole of the framework it'的一部分是不可变的......

(编辑完3)

我到目前为止提出的选项:

  • Add :在.NET中很常见,但意味着原始列表的变异

  • Cons :我认为这是函数式语言中的正常名称,但对于没有这些语言经验的人来说毫无意义

  • Plus :到目前为止我最喜欢的,它并不意味着我的变异 . 显然这也是used in Haskell但是期望略有不同(Haskell程序员可能期望它将两个列表一起添加而不是将一个值添加到另一个列表中) .

  • With :与其他一些不可变约定一致,但与IMO没有完全相同的"additionness" .

  • And :不是很具描述性 .

  • 运营商超载:我真的不愿意被说服!

我用来选择的标准是:

  • 给出方法调用结果的正确印象(即它是带有额外元素的原始列表)

  • 尽可能清楚地表明它不会改变现有列表

  • 如上面第二个例子中链接在一起时听起来很合理

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

EDIT 1: 这是我更喜欢 PlusAdd 的理由 . 考虑以下两行代码:

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

在我看来(这是个人的事情),后者显然是错误的 - 它可以,直到你记得它改变它的操作数是 Plus 是我最喜欢的另一个原因 . 如果没有操作符重载的轻微瑕疵,它仍然给出相同的内涵,其中包括(对我来说)不改变操作数(或者在这种情况下是方法目标) .

EDIT 2: 不喜欢的原因添加 .

各种答案都是有效的:“Go with Add . 这就是 DateTime 的作用,而 StringReplace 方法等等,这里优先考虑't make the immutability obvious." I agree - there' . 然而,我看到很多人打电话给 DateTime.AddString.Replace 并期待突变 . 有很多新闻组问题(如果我挖的话可能是那些问题),这些问题的回答是“你忽略了 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> :)那样具有自我描述性 .

30 回答

  • 13

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

    或者我非常喜欢 AfterAppending

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

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

    但是,没有命名选择会让每个人都清楚,所以我个人认为一个好的xml doc评论会在这里走很长的路 . 当你在IDE中编写代码时,VS会把这些放在你的脸上 - 它们很难被忽视 .

  • 33

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

  • 22

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

  • 10

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

  • 11

    如果你觉得自己很啰嗦,我会称之为 Extend() 或者也许是 ExtendWith() .

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

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

  • 5

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

  • 21

    首先,一个有趣的起点:http://en.wikipedia.org/wiki/Naming_conventions_(programming) ...特别是,检查底部的"See Also"链接 .

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

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

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

    表达不可变语义是我喜欢通过上下文做的事情 . 也就是说,我已经完成了,它在同一个地方完成了很多工作;可变性是个例外 .

  • 4

    也许混淆源于你想要两个操作合二为一的事实 . 为什么不将它们分开? DSL风格:

    var list = new ImmutableList<string>("Hello");
    var list2 = list.Copy().With("World!");
    

    Copy 将返回一个中间对象,这是原始列表的可变副本 . With 将返回一个新的不可变列表 .

    Update:

    但是,拥有一个中间的,可变的集合并不是一个好方法 . 中间对象应包含在 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);
    }
    

    现在用户不可能误解,他们会 naturally fall into the pit of success .

    Yet another update:

    如果您仍然包含't like the mutable list mention, even now that it',则可以设计一个规范对象,该对象将指定或编写复制操作将如何转换其列表 . 用法是一样的:

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

    现在,您可以使用规则名称进行创作,并且只能公开您希望支持的功能,而不是 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())
    );
    
  • 18

    每当我遇到命名的果酱时,我都会打起互联网 .

    thesaurus.com为"add"返回此信息:

    定义:adjoin,increase;进一步评论别名: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 ,连接,包括,杰克,爵士,联合,垫,parlay,背驮式,插入,倒,回复,跑起来,进一步说,拍打,雪球,汤,加快,穗,加强,补充,甜化,粘贴,标记

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

  • 9

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

  • 58

    list.CopyWith(element)

    和Smalltalk一样:)

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

  • 9

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

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

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

    object.AlongWith("this new item");
    
  • 50

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

    你要阻止你的用户将对象误认为是可变的东西的唯一方法是通过明确的方式将其显式化对象本身或通过方法的名称(与“GetCopyWith”或“CopyAndAdd”等详细选项一样) .

    所以请选择你最喜欢的“Plus” .

  • 48

    添加(),附加()

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

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

  • 119

    一些随意的想法:

    • ImmutableAdd()

    • 追加()

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

  • 5

    看着http://thesaurus.reference.com/browse/addhttp://thesaurus.reference.com/browse/plus我发现 gainaffix 但是我不确定他们有多么暗示非突变 .

  • 128

    在这种情况下,我通常会使用 Concat . 这通常意味着我正在创建一个新对象 .

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

    我最终在BclExtras中使用Add来获取所有不可变集合 . 原因是因为类型的名称以Immutable为前缀,所以人们并不担心混淆Add和变异添加 .

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

    其他名称:你提到过:

    • 加上:我认为它不是一个非变异操作,而是Add

    • With:会导致VB问题(双关语)

    • 运算符重载:可发现性是一个问题

    我考虑的选项:

    • Concat:String 's are Immutable and use this. Unfortunately it'只对添加到结尾非常有用

    • CopyAdd:复制什么?来源,清单?

    • AddToNewList:也许是List的好词 . 但是收集,堆栈,队列等等呢......

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

    • 绝对是一个不可变的操作

    • 对大多数用户都是可以理解的

    • 可用少于4个字表示

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

    Edit: 对Plus编辑的响应

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

    list.Minus(obj);
    

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

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

    Edit 2

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

    但是我认为ImmutableList是一个不同的参数 . String或DateTime没有任何东西将它 Build 为程序员不可变 . 你必须简单地知道它是通过其他来源不可变的 . 所以混乱并不意外 .

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

    Edit 3: TestSuite这样的类型是不可变的但不包含这个词呢?

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

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

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

    • 前缀为Immutable:ImmutableTestSuite

    • 添加描述Immutablitiy等级的属性 . 这当然不太容易被发现

    • 其他不多 .

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

  • 9

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

    也许我会使用这个方案

    AddToCopy
    RemoveFromCopy
    InsertIntoCopy
    

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

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

    Add 1 to 2 and you get 3
    

    嗯,当然,2仍然是2,你得到一个新的数字 . 这是关于两个数字,而不是列表和元素,但我认为它有一些类比 . 在我看来, add 并不一定意味着你会改变某些东西 . 我当然认为你的观点是,只有一个包含 add 并且不使用返回的新对象的孤独语句看起来并不错 . 但是我想出了另一个名字,却没有让我想到"hmm, i would need to look at the documentation to know what it is about"因为它的名字与我所期望的名称不同"add" . 从litb看起来只是一些奇怪的想法,不确定它是否有意义:)

  • 16

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

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

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

  • 8

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

  • 6

    我喜欢mmyers建议的 CopyAndAdd . 为了与"mutation"主题保持一致,也许你可以选择 Bud (无性繁殖), GrowReplicateEvolve ? =)

    编辑:继续我的遗传主题, Procreate 怎么样,暗示一个新的对象是基于前一个,但添加了一些新的东西 .

  • 13

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

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

    • 对于没有FP经验的人来说,这实际上是一个很大的优势 . 正如你所指出的,你发现的所有其他词语已经有了一些含义,而且这个含义要么略有不同,要么含糊不清 . 一个新概念应该有一个新词(或者在这种情况下,一个旧词) . 我宁愿有人必须查找Cons的定义,而不是假设他错误地知道Add的作用 .

    • 从函数式语言借用的其他操作通常保留其原始名称,没有明显的灾难 . 我还没有看到任何关于“非常”的“ Map ”和“减少”的同义词,这些声音对于非FP的人来说更为熟悉,我也没有看到这样做的任何好处 .

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

  • 14

    Chain()或Attach()怎么样?

  • 7

    对于那些住在那里的人来说, matemateWithcoitus 怎么样?就繁殖而言,哺乳动物通常被认为是不可改变的 .

    还要把 Union 扔出去 . 借用SQL .

  • 5

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

    其他一些可能性:

    拼接()

    接枝()

    合生()

  • 4

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

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

    我认为这可能是一种罕见的情况,其中可以接受 + 运算符的重载 . 在数学术语中,我们知道 + 并没有附加某些内容 . 它总是将两个值组合在一起并返回一个新的结果值 .

    例如,当你说时,直觉上很明显

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

  • 5

    Join 似乎合适 .

相关问题