What's the best name for a non-mutating “add”

2019-01-07 03:22发布

Sorry for the waffly title - if I could come up with a concise title, I wouldn't have to ask the question.

Suppose I have an immutable list type. It has an operation Foo(x) which returns a new immutable list with the specified argument as an extra element at the end. So to build up a list of strings with values "Hello", "immutable", "world" you could write:

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

(This is C# code, and I'm most interested in a C# suggestion if you feel the language is important. It's not fundamentally a language question, but the idioms of the language may be important.)

The important thing is that the existing lists are not altered by Foo - so empty.Count would still return 0.

Another (more idiomatic) way of getting to the end result would be:

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

My question is: what's the best name for Foo?

EDIT 3: As I reveal later on, the name of the type might not actually be ImmutableList<T>, which makes the position clear. Imagine instead that it's TestSuite and that it's immutable because the whole of the framework it's a part of is immutable...

(End of edit 3)

Options I've come up with so far:

  • 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!

The criteria I'm using for choosing are:

  • Gives the correct impression of the result of the method call (i.e. that it's the original list with an extra element)
  • Makes it as clear as possible that it doesn't mutate the existing list
  • Sounds reasonable when chained together as in the second example above

Please ask for more details if I'm not making myself clear enough...

EDIT 1: Here's my reasoning for preferring Plus to Add. Consider these two lines of code:

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

In my view (and this is a personal thing) the latter is clearly buggy - it's like writing "x + 5;" as a statement on its own. The first line looks like it's okay, until you remember that it's immutable. In fact, the way that the plus operator on its own doesn't mutate its operands is another reason why Plus is my favourite. Without the slight ickiness of operator overloading, it still gives the same connotations, which include (for me) not mutating the operands (or method target in this case).

EDIT 2: Reasons for not liking Add.

Various answers are effectively: "Go with Add. That's what DateTime does, and String has Replace methods etc which don't make the immutability obvious." I agree - there's precedence here. However, I've seen plenty of people call DateTime.Add or String.Replace and expect mutation. There are loads of newsgroup questions (and probably SO ones if I dig around) which are answered by "You're ignoring the return value of String.Replace; strings are immutable, a new string gets returned."

Now, I should reveal a subtlety to the question - the type might not actually be an immutable list, but a different immutable type. In particular, I'm working on a benchmarking framework where you add tests to a suite, and that creates a new suite. It might be obvious that:

var list = new ImmutableList<string>();
list.Add("foo");

isn't going to accomplish anything, but it becomes a lot murkier when you change it to:

var suite = new TestSuite<string, int>();
suite.Add(x => x.Length);

That looks like it should be okay. Whereas this, to me, makes the mistake clearer:

var suite = new TestSuite<string, int>();
suite.Plus(x => x.Length);

That's just begging to be:

var suite = new TestSuite<string, int>().Plus(x => x.Length);

Ideally, I would like my users not to have to be told that the test suite is immutable. I want them to fall into the pit of success. This may not be possible, but I'd like to try.

I apologise for over-simplifying the original question by talking only about an immutable list type. Not all collections are quite as self-descriptive as ImmutableList<T> :)

30条回答
别忘想泡老子
2楼-- · 2019-01-07 04:04

Actually I like And, especially in the idiomatic way. I'd especially like it if you had a static readonly property for the Empty list, and perhaps make the constructor private so you always have to build from the empty list.

var list = ImmutableList<string>.Empty.And("Hello")
                                      .And("Immutable")
                                      .And("Word");
查看更多
forever°为你锁心
3楼-- · 2019-01-07 04:05

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.

查看更多
疯言疯语
4楼-- · 2019-01-07 04:05

Whenever I'm in a jam with nomenclature, I hit up the interwebs.

thesaurus.com returns this for "add":

Definition: adjoin, increase; make further comment

Synonyms: affix, annex, ante, append, augment, beef up, boost, build up, charge up, continue, cue in, figure in, flesh out, heat up, hike, hike up, hitch on, hook on, hook up with, include, jack up, jazz up, join together, pad, parlay, piggyback, plug into, pour it on, reply, run up, say further, slap on, snowball, soup up, speed up, spike, step up, supplement, sweeten, tack on, tag

I like the sound of Adjoin, or more simply Join. That is what you're doing, right? The method could also apply to joining other ImmutableList<>'s.

查看更多
Fickle 薄情
5楼-- · 2019-01-07 04:06

I think the key thing you're trying to get at that's hard to express is the nonpermutation, so maybe something with a generative word in it, something like CopyWith() or InstancePlus().

查看更多
【Aperson】
6楼-- · 2019-01-07 04:06

First, an interesting starting point: http://en.wikipedia.org/wiki/Naming_conventions_(programming) ...In particular, check the "See Also" links at the bottom.

I'm in favor of either Plus or And, effectively equally.

Plus and And are both math-based in etymology. As such, both connote mathematical operation; both yield an expression which reads naturally as expressions which may resolve into a value, which fits with the method having a return value. And bears additional logic connotation, but both words apply intuitively to lists. Add connotes action performed on an object, which conflicts with the method's immutable semantics.

Both are short, which is especially important given the primitiveness of the operation. Simple, frequently-performed operations deserve shorter names.

Expressing immutable semantics is something I prefer to do via context. That is, I'd rather simply imply that this entire block of code has a functional feel; assume everything is immutable. That might just be me, however. I prefer immutability to be the rule; if it's done, it's done a lot in the same place; mutability is the exception.

查看更多
聊天终结者
7楼-- · 2019-01-07 04:07

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");
}
查看更多
登录 后发表回答