What's the best name for a non-mutating "add" method on an immutable collection?

Language AgnosticNaming ConventionsListImmutability

Language Agnostic Problem Overview


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> :)

Language Agnostic Solutions


Solution 1 - Language Agnostic

In situations like that, I usually go with Concat. That usually implies to me that a new object is being created.

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

Solution 2 - Language Agnostic

I'd go with Cons, for one simple reason: it means exactly what you want it to.

  1. I'm a huge fan of saying exactly what I mean, especially in source code. A newbie will have to look up the definition of Cons only once, but then read and use that a thousand times. I find that, in the long term, it's nicer to work with systems that make the common case easier, even if the up-front cost is a little bit higher.

  2. The fact that it would be "meaningless" to people with no FP experience is actually a big advantage. As you pointed out, all of the other words you found already have some meaning, and that meaning is either slightly different or ambiguous. A new concept should have a new word (or in this case, an old one). I'd rather somebody have to look up the definition of Cons, than to assume incorrectly he knows what Add does.

  3. Other operations borrowed from functional languages often keep their original names, with no apparent catastrophes. I haven't seen any push to come up with synonyms for "map" and "reduce" that sound more familiar to non-FPers, nor do I see any benefit from doing so.

(Full disclosure: I'm a Lisp programmer, so I already know what Cons means.)

Solution 3 - Language Agnostic

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

Solution 4 - Language Agnostic

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.

Solution 5 - Language Agnostic

Personally, I like .With(). If I was using the object, after reading the documentation or the code comments, it would be clear what it does, and it reads ok in the source code.

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

Or, you add "Along" with it.. :)

object.AlongWith("this new item");

Solution 6 - Language Agnostic

I ended up going with Add for all of my Immutable Collections in BclExtras. The reason being is that it's an easy predictable name. I'm not worried so much about people confusing Add with a mutating add since the name of the type is prefixed with Immutable.

For awhile I considered Cons and other functional style names. Eventually I discounted them because they're not nearly as well known. Sure functional programmers will understand but they're not the majority of users.

Other Names: you mentioned:

  • Plus: I'm wishy/washing on this one. For me this doesn't distinguish it as being a non-mutating operation anymore than Add does
  • With: Will cause issues with VB (pun intended)
  • Operator overloading: Discoverability would be an issue

Options I considered:

  • Concat: String's are Immutable and use this. Unfortunately it's only really good for adding to the end
  • CopyAdd: Copy what? The source, the list?
  • AddToNewList: Maybe a good one for List. But what about a Collection, Stack, Queue, etc ...

Unfortunately there doesn't really seem to be a word that is

  1. Definitely an immutable operation
  2. Understandable to the majority of users
  3. Representable in less than 4 words

It gets even more odd when you consider collections other than List. Take for instance Stack. Even first year programmers can tell you that Stacks have a Push/Pop pair of methods. If you create an ImmutableStack and give it a completely different name, lets call it Foo/Fop, you've just added more work for them to use your collection.

Edit: Response to Plus Edit

I see where you're going with Plus. I think a stronger case would actually be Minus for remove. If I saw the following I would certainly wonder what in the world the programmer was thinking

list.Minus(obj);

The biggest problem I have with Plus/Minus or a new pairing is it feels like overkill. The collection itself already has a distinguishing name, the Immutable prefix. Why go further by adding vocabulary whose intent is to add the same distinction as the Immutable prefix already did.

I can see the call site argument. It makes it clearer from the standpoint of a single expression. But in the context of the entire function it seems unnecessary.

Edit 2

Agree that people have definitely been confused by String.Concat and DateTime.Add. I've seen several very bright programmers hit this problem.

However I think ImmutableList is a different argument. There is nothing about String or DateTime that establishes it as Immutable to a programmer. You must simply know that it's immutable via some other source. So the confusion is not unexpected.

ImmutableList does not have that problem because the name defines it's behavior. You could argue that people don't know what Immutable is and I think that's also valid. I certainly didn't know it till about year 2 in college. But you have the same issue with whatever name you choose instead of Add.

Edit 3: What about types like TestSuite which are immutable but do not contain the word?

I think this drives home the idea that you shouldn't be inventing new method names. Namely because there is clearly a drive to make types immutable in order to facilitate parallel operations. If you focus on changing the name of methods for collections, the next step will be the mutating method names on every type you use that is immutable.

I think it would be a more valuable effort to instead focus on making types identifiable as Immutable. That way you can solve the problem without rethinking every mutating method pattern out there.

Now how can you identify TestSuite as Immutable? In todays environment I think there are a few ways

  1. Prefix with Immutable: ImmutableTestSuite
  2. Add an Attribute which describes the level of Immutablitiy. This is certainly less discoverable
  3. Not much else.

My guess/hope is development tools will start helping this problem by making it easy to identify immutable types simply by sight (different color, stronger font, etc ...). But I think that's the answer though over changing all of the method names.

Solution 7 - Language Agnostic

I think this may be one of those rare situations where it's acceptable to overload the + operator. In math terminology, we know that + doesn't append something to the end of something else. It always combines two values together and returns a new resulting value.

For example, it's intuitively obvious that when you say

x = 2 + 2;

the resulting value of x is 4, not 22.

Similarly,

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

should make clear what each variable is going to hold. It should be clear that list2 is not changed in the last line, but instead that list3 is assigned the result of appending "word" to list2.

Otherwise, I would just name the function Plus().

Solution 8 - Language Agnostic

To be as clear as possible, you might want to go with the wordier CopyAndAdd, or something similar.

Solution 9 - Language Agnostic

I would call it Extend() or maybe ExtendWith() if you feel like really verbose.

Extends means adding something to something else without changing it. I think this is very relevant terminology in C# since this is similar to the concept of extension methods - they "add" a new method to a class without "touching" the class itself.

Otherwise, if you really want to emphasize that you don't modify the original object at all, using some prefix like Get- looks like unavoidable to me.

Solution 10 - Language Agnostic

I like mmyers suggestion of CopyAndAdd. In keeping with a "mutation" theme, maybe you could go with Bud (asexual reproduction), Grow, Replicate, or Evolve? =)

EDIT: To continue with my genetic theme, how about Procreate, implying that a new object is made which is based on the previous one, but with something new added.

Solution 11 - Language Agnostic

Added(), Appended()

I like to use the past tense for operations on immutable objects. It conveys the idea that you aren't changing the original object, and it's easy to recognize when you see it.

Also, because mutating method names are often present-tense verbs, it applies to most of the immutable-method-name-needed cases you run into. For example an immutable stack has the methods "pushed" and "popped".

Solution 12 - Language Agnostic

This is probably a stretch, but in Ruby there is a commonly used notation for the distinction: add doesn't mutate; add! mutates. If this is an pervasive problem in your project, you could do that too (not necessarily with non-alphabetic characters, but consistently using a notation to indicate mutating/non-mutating methods).

Solution 13 - Language Agnostic

Join seems appropriate.

Solution 14 - Language Agnostic

Maybe the confusion stems from the fact that you want two operations in one. Why not separate them? DSL style:

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

Copy would return an intermediate object, that's a mutable copy of the original list. With would return a new immutable list.

Update:

But, having an intermediate, mutable collection around is not a good approach. The intermediate object should be contained in the Copy operation:

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

Now, the Copy operation takes a delegate, which receives a mutable list, so that it can control the copy outcome. It can do much more than appending an element, like removing elements or sorting the list. It can also be used in the ImmutableList constructor to assemble the initial list without intermediary immutable lists.

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);
}

Now there's no possibility of misinterpretation by the users, they will naturally fall into the pit of success.

Yet another update:

If you still don't like the mutable list mention, even now that it's contained, you can design a specification object, that will specify, or script, how the copy operation will transform its list. The usage will be the same:

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

Now you can be creative with the rules names and you can only expose the functionality that you want Copy to support, not the entire capabilities of an IList.

For the chaining usage, you can create a reasonable constructor (which will not use chaining, of course):

public ImmutableList(params T[] elements) ...

...

var list = new ImmutableList<string>("Hello", "immutable", "World");

Or use the same delegate in another constructor:

var list = new ImmutableList<string>(rules => 
  rules
    .Append("Hello")
    .Append("immutable")
    .Append("World")
);

This assumes that the rules.Append method returns this.

This is what it would look like with your latest example:

var suite = new TestSuite<string, int>(x => x.Length);
var otherSuite = suite.Copy(rules => 
  rules
    .Append(x => Int32.Parse(x))
    .Append(x => x.GetHashCode())
);

Solution 15 - Language Agnostic

A few random thoughts:

  • ImmutableAdd()
  • Append()
  • ImmutableList<T>(ImmutableList<T> originalList, T newItem) Constructor

Solution 16 - Language Agnostic

DateTime in C# uses Add. So why not use the same name? As long the users of your class understand the class is immutable.

Solution 17 - Language Agnostic

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

Solution 18 - Language Agnostic

I don't think the English language will let you imply immutability in an unmistakable way while using a verb that means the same thing as "Add". "Plus" almost does it, but people can still make the mistake.

The only way you're going to prevent your users from mistaking the object for something mutable is by making it explicit, either through the name of the object itself or through the name of the method (as with the verbose options like "GetCopyWith" or "CopyAndAdd").

So just go with your favourite, "Plus."

Solution 19 - Language Agnostic

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.

Solution 20 - Language Agnostic

How about Chain() or Attach()?

Solution 21 - Language Agnostic

I prefer Plus (and Minus). They are easily understandable and map directly to operations involving well known immutable types (the numbers). 2+2 doesn't change the value of 2, it returns a new, equally immutable, value.

Some other possibilities:

Splice()

Graft()

Accrete()

Solution 22 - Language Agnostic

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.

Solution 23 - Language Agnostic

I think "Add" or "Plus" sounds fine. The name of the list itself should be enough to convey the list's immutability.

Solution 24 - Language Agnostic

Maybe there are some words which remember me more of making a copy and add stuff to that instead of mutating the instance (like "Concatenate"). But i think having some symmetry for those words for other actions would be good to have too. I don't know of a similar word for "Remove" that i think of the same kind like "Concatenate". "Plus" sounds little strange to me. I wouldn't expect it being used in a non-numerical context. But that could aswell come from my non-english background.

Maybe i would use this scheme

AddToCopy
RemoveFromCopy
InsertIntoCopy

These have their own problems though, when i think about it. One could think they remove something or add something to an argument given. Not sure about it at all. Those words do not play nice in chaining either, i think. Too wordy to type.

Maybe i would just use plain "Add" and friends too. I like how it is used in math

Add 1 to 2 and you get 3

Well, certainly, a 2 remains a 2 and you get a new number. This is about two numbers and not about a list and an element, but i think it has some analogy. In my opinion, add does not necessarily mean you mutate something. I certainly see your point that having a lonely statement containing just an add and not using the returned new object does not look buggy. But I've now also thought some time about that idea of using another name than "add" but i just can't come up with another name, without making me think "hmm, i would need to look at the documentation to know what it is about" because its name differs from what I would expect to be called "add". Just some weird thought about this from litb, not sure it makes sense at all :)

Solution 25 - Language Agnostic

How about mate, mateWith, or coitus, for those who abide. In terms of reproducing mammals are generally considered immutable.

Going to throw Union out there too. Borrowed from SQL.

Solution 26 - Language Agnostic

Looking at http://thesaurus.reference.com/browse/add and http://thesaurus.reference.com/browse/plus I found gain and affix but I'm not sure how much they imply non-mutation.

Solution 27 - Language Agnostic

I think that Plus() and Minus() or, alternatively, Including(), Excluding() are reasonable at implying immutable behavior.

However, no naming choice will ever make it perfectly clear to everyone, so I personally believe that a good xml doc comment would go a very long way here. VS throws these right in your face when you write code in the IDE - they're hard to ignore.

Solution 28 - Language Agnostic

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

Solution 29 - Language Agnostic

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.

Solution 30 - Language Agnostic

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.

Solution 31 - Language Agnostic

Maybe a static method or an operator (which is static) would be best. It would take responsibility away from the instances, and users will know right away that the operation doesn't belong to any of the instances. It's specially important NOT to use extension methods, since their resemblance to instance methods upon usage defeats the purpose.

The static method could be called 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!");

But I'd prefer that C# had class-free functions here. Or at least something like Java's static import facility.

The operator could be +:

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

But I'd rather be able to use something else like <<, :: or ., which are not possible in C#.

Also, static members look more functional and I think lend themselves better to this immutable view.

Solution 32 - Language Agnostic

I personally like unite(), as when you unite objects you still preserve their individuality, but the union of them is a separate new entity. Union is similar as suggested but is already well defined in set theory and unite is more verby and says to me that following the method I have a new enitity. I know its late but hey couldn't find the suggestion on the list. Plus the word reminds me of the days of old and uniting people to go to war.. hehe

Solution 33 - Language Agnostic

2 suggestions:

A "free" function:

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

A constructor overload (which is, in a way, a variation on the "free function" theme):

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

Solution 34 - Language Agnostic

How about cloneWith?

Reasons:

  1. For the single word names suggested, I would not know for sure what they do until I checked the documentation.
  2. For the compound names suggested thus far, I like cloneWith better. I would know exactly what I was getting with this method name, it is relatively concise, it is easy to remember, and it just "feels" right :)
  3. With modern code-completion in most programming tools, longer names are easier to work with than ever before.

Though many times conciseness adds to clarity, take clarity over conciseness if you have to choose...

In Action:

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

Solution 35 - Language Agnostic

The name WithAdded reads nicely and is IMHO better than Added which can be read as an adjective.

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

Or for a slightly more verbose version:

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

Solution 36 - Language Agnostic

I'm a little late to the party, but I didn't see an answer that suggested simply not doing it at all! Let it stay immutable. Any method you put is going to open to abuse when they put it into a loop, which will happen eventually. Instead, I'd advise using a builder instead.

MyImmutableBuilder builder = new MyImmutableBuilder(someImmutable);
MyImmutable modifiedImmultable = builder.add(element1).add(element2).build();

Now in the case of an ImmutableList, your builder would really just be a List, most likely.

I guess it all boils down to... to you really want an easy way to add just a single element to your immutable collection? If it's a common occurrence, you probably don't want to be using an immutable object (you can always call build() any time you want to send a snapshot of the object at it's present state...) If it's not a common occurrence, then having a builder as a requirement to do it wouldn't be a significant impediment, especially if it were documented that this is how you want to build them.

@supercat - consider the following scenario you describe:

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?

Solution 37 - Language Agnostic

I would go with list.NewList("word") because it describes what you are doing (creating a new list).

I must agree it doesn't imply that the argument is added to the end of the list, but personally I belong to the succinct-if-possible camp, so I'd favour list.NewList("word") over list.NewListAfterAppend("word").

Solution 38 - Language Agnostic

Any name that implies that an object of the same type will be returned should be fine to use. Plus is a good name for this, as if you plus two objects you expect the result to be returned.

Plus just doesn't sound like the correct name to use in this instance though, since you're 'Plus'ing a test into a test suite.

GetWith() sounds like an option to me. Or ever GetTypeWith() where type is obviously the type your using. So for example:

var list = new ImmutableList<String>();
var list2 = list.GetWith("First");
var list3 = list2.GetWith("Second");

// OR

var list2 = list.GetListWith("First");

The Get implies you're getting the list that's already contained, and the With implies you want another object along with it. CopyWith() would also meet this criteria.

The immediate problem I see with GetWith is that it's not easily guessable. A developer wants to add a suite, not get the current suite. I'd immediately type .Add and hope intellisence showed something very close to what I'd expect.

Solution 39 - Language Agnostic

As a c++ programmer and fan of the STL I put forth add_copy. (this would also suggest remove_copy, replace_copy and so on)

Solution 40 - Language Agnostic

I would personally go with AddVoid or the other way around of VoidAdd

Solution 41 - Language Agnostic

If you're a functional programmer, this has a few names:

(++)

pronounced "append". Or it could be concat, depending on your types:

-- join two things into one thing:
append :: a -> a -> a    

-- join many things into one thing
concat :: [a] -> a

Or you might mean (:), AKA cons:

(:) :: a -> [a] -> [a]    

if you're joining things onto the front of the list, snoc if it goes on the end.

At least that's what we've been calling appending things onto lists in Haskell-land for the last 20 years.


Note, this is not arithmetic (+), since it is monoidal, not a ring.

Solution 42 - Language Agnostic

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.

So thinking more along the lines of finding a name that does not imply a modification to the original list and also suggest that a new list is created, consider the following:

  1. 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.
  2. 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.
  3. 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.

Solution 43 - Language Agnostic

copyWithSuffix: would be a custom method name in a similar vein to the Objective-C immutable string copy method stringByAppendingString:.

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

Suffix communicates the addition-ness of it and Copy makes the immutability clear. Feel free to replace Suffix with something more logical for the sort of test suite it actually is (maybe you're not suffix-ing these to one big internal string, you could be providing test case names/parameters for all I know).

Solution 44 - Language Agnostic

1) Question analysis
abstract of the question can be :
From an immutable ... get a new immutable but different from the original one ..
In this current question context :
From an immutable List get a new immutable list having a difference of a new element in addition in the end.

Can you give a effective "verb" ("method" in programming language) that express the action in a concise way without using the simple "Add" verb.

2) Proposal analysis
First concept : Immutable give a similar immutable ,
>>"copy" verb express conservation in "content" but less for it defined constraints (immutable)
>>"clone" verb express conservative in "content" but also for its defined constraints.
>>"twin" verb is similar to clone but not common in software , but it's short and sound good.

Second concept : the result give something different from the original
>>"add" express an action to make the difference between original and the new object but by definition we do not act (mutate) an immutable.
>>"plus" express the fact that verb result will be augmented without disturbing the original object ... "adverb" approach is more "immutable" friendly
>>"with" as before it express the fact that "verb" will do something more but may be ambigous of what it will doing more. Can also express the fact the "verb parameter" is the "more" of the "verb"

3) Answers
With verb "clone"
>> augmentClone
>> growClone
>> extendClone
with "with"
>> cloneWith
>> augmentCloneWith
>> growCloneWith
>> extendCloneWith

With verb "twin"
>> augmentTwin
>> growTwin
>> extendTwin
with "with"
>> twinWith
>> augmentTwinWith
>> growTwinWith
>> extendTwinWith

Solution 45 - Language Agnostic

While naming the method correctly can decrease the chance of misuse, if there was some language construct that told the compiler: "This method does nothing but return a new object, it should be used or the method call is meaningless" and then the compiler could complain with an error/warning whenever someone uses the method in a wrong setup.

I've filled a feature request for this feel free to vote if you agree.

Solution 46 - Language Agnostic

I Like And(). I think it has the least potential for ambiguity. The only clash I can think of is with a logical And, I don't see that being a problem with a C# developer and even for VB I think the context makes it unlikely to cause a problem and any issue would be picked up quickly at compile time. It also works well in in English "Do something to These And That" or "Put These And That in the box".

I think .With() is OK. My concern is it may look a little like a linq Where<> method especially if there's a lambda as an argument. The English in my head is also less clear especially "Do something to These With That".

I don't like .Plus(). I can't get past it as a synonym for Add: plus = plus sign = + = add.

Solution 47 - Language Agnostic

"Replace"? It doesn't add to the list, it replaces the list with a new one.

Solution 48 - Language Agnostic

I would go for the simple Add(). An alternative would be Append(), if you want to convey that this is really a collection operation.

In addition to the explicit method, I'd still suggest implementing the obverloaded + operatr. It's a well known operation. Everybody knows String is immutable, yet everybody uses the '+' to build new instances of it.

Solution 49 - Language Agnostic

How about "Augment"?

It's a different word from Add, but it's a close synonym.

Solution 50 - Language Agnostic

Since the type name is ImmutableList thus specifying that it is infact immutable, I think that .Add() is fine. However, If your really insistant on something else, I might go with something like .AddEx() where Ex means extended and implies that the user should determine what that Ex is (by reading docs) before using. I also like the suggestion of Plus() and GetCopyWith()

Solution 51 - Language Agnostic

.Trail implies a very strong understanding of the list has not changed, this object is trailing behind the list, it has not been added to it.

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

Solution 52 - Language Agnostic

"add()"

The fact it returns a new list is immaterial thats an implementation detail revealed by the signature. The main action that the method accomplishes is "adding" a new element to a list. How or what it deos or returns should not be part of the method name. If a method was synchronized would that affect the method name -"synchronizedAdd()" ??? - of course not.

Classes like String which follow the would-be-mutator pattern still have really simple method names - none are compounded words.

Solution 53 - Language Agnostic

So I guess a method named "ImmutableAdd()" is entirely too simplistic?

Solution 54 - Language Agnostic

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

Or "Attach" or "AttachTo".

Solution 55 - Language Agnostic

I would use a constructor.

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

f1 contains "one". f2 contains "one", "two". f3 contains "one", "two", "three".

Solution 56 - Language Agnostic

I'm arriving a bit late here, how about NewWith?

Solution 57 - Language Agnostic

I would call it ToInclude

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

idiomatically (?)

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

   

Works for the case you mentioned too.

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

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

Solution 58 - Language Agnostic

Very late to the game, but how about Freeze. There is precedence in WPF for using Freeze and IsFrozen to test if an object is mutable. Granted, this skews the meaning a little in that typically Freeze() is meant as a way to make the current object immutable, but if it has a parameter to it, you could see that you are getting something that is immutable.

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

Basically:

  1. It is one word
  2. The connotation revolves around immutability.
  3. Precendence in WPF for "similar" syntax.

Solution 59 - Language Agnostic

How about an Extension method? You could call it Join in this case. Being an extension method, users should know that it is a static method and might therefore give them a little pause and encourage them to look at the return value. At the same time, you have the usability of an "instance" method.

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);
}

and then later on...

var list = new ImmutableList<string>().Join("Hello")
                                      .Join("Extensible")
                                      .Join("World");

I don't quite know the accepted behavior on posting multiple answers, but this is an interesting question since I think that nomenclature is a critical step in design and my brain keeps pondering on this one.

Solution 60 - Language Agnostic

C#-ish pseudo code follows:

interface Foo
{
    // Constructors
    Foo();
    Foo(params Foo[] foos);
    
    // Instance method
    Foo Join(params Foo[] foos);

    // Class method
    static Foo Join(params Foo[] foos);
}    

So you could call things like this:

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

Solution 61 - Language Agnostic

How about creating a wrapper class with an Augment (or AugmentWith) method?

Solution 62 - Language Agnostic

Since this question is now basically a thesaurus: How about .Bring(). As in, give me this list and bring this element with it?

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

It doesn't roll off the tongue, but it means it, to me.

Actually, AndBring() might be even better.

Solution 63 - Language Agnostic

I'd go with operator overloading +. The reason is that that's the way it works in Python - .append() on a list mutates the list, while doing + with another list creates a new list. + also definitely does not imply mutation. I think that's why you like .Plus() so much, so if you don't want to operator overload, then you can go with .Plus().

Solution 64 - Language Agnostic

list.copyAndAppend(elt)

How does that sound?)

Solution 65 - Language Agnostic

As was previously mentioned, you're trying to do 2 things at once and micro-optimizing just for that purpose. If copying occurs away from original collection definition, names like "Add","Append" will only confuse.

"CloneAppend" is what I might use in this situation. Something tells me I wouldn't be in this situation. I believe that soon you'll find yourself in need of other kinds of similar operations like "CloneFirstN" or "CloneRemoveLast". And soon you'll realize that it's much better to chain the clone/copy method, append/remove whatever you need, then convert the collection back to immutable even if it takes an extra line of code.

Solution 66 - Language Agnostic

Personally I would call the method Clone and call the parameter AdditionalValue as that is essentially what it appears to be doing and would be easily understandable e.g.

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

Solution 67 - Language Agnostic

For this kind of functions I usually use the verb at the second form, Added in this case.

This convention is used by Qt, for example QVector2D::normalized returns a normalized vector, while QVector2D::normalize normalizes a vector.

In the same way Added would return the object with a new added item.

Solution 68 - Language Agnostic

I would go with "CreateNewListWithAdditionalItems"

I dont mind long names, but this one is telling you what it will actually do. Also I would throw an exception if you use Add or any other altering methods.

Solution 69 - Language Agnostic

Borrowing from C, how about Concat

Solution 70 - Language Agnostic

The problem with methods like String.Replace is that the user can mistakenly think that there's mutation going on because he can ignore the return value. So use an out parameter for the "return" value. The user can't ignore that:

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) {
    // ...
  }
}

Usage:

var list = new ImmutableList<string>("Hello", "Immutable");
ImmutableList<string> newList;
list.Add(out newList, "World");

Solution 71 - Language Agnostic

Personally I'd go with Pad(..) perhaps if you're after a fluent style, also with an extension method of AndWith(..)

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

Solution 72 - Language Agnostic

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.

Solution 73 - Language Agnostic

A very late answer, but I wanted to add my two cents: I think the point here could be the verb tense more than the verb itself:

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

The participle changes the meaning, in my opinion: we are no adding anything to myList, but returning the result of the operation.

Solution 74 - Language Agnostic

Another point in favor of Plus is the new mostly immutable Java time API, where plus() is for example used to add to Instants.

Solution 75 - Language Agnostic

Instead/In addition to a name, immutable containers collections are a classic case for operator overloading (as is already the case for int/string/etc). There are two advantages here:

  • conciseness: l1 = l + o1 + o2 rather than l1 = l.Add(o1).Add(o2)

  • using assignment operators: l += o rather than l = l.Add(o)

Using operators also makes the code less error prone, it is common when switching from mutable to immutable types to forget the assignment and just write ie l.Add(o); (with disastrous effects) however just writing l+o; without using the result really sticks out.

You can see this in action in the collections that come as part of the F package.

Solution 76 - Language Agnostic

Consistency in those things is important, I like to follow the naming conventions in Swift API Design Guidelines:

> - Name functions and methods according to their side-effects > - Those without side-effects should read as noun phrases, e.g. > x.distance(to: y), i.successor(). > - Those with side-effects should read as imperative verb phrases, e.g., > print(x), x.sort(), x.append(y). > - Name mutating/non-mutating method pairs consistently. A mutating > method will often have a non-mutating variant with similar semantics, > but that returns a new value rather than updating an instance in-place. > > - When the operation is naturally described by a verb, use the verb’s > imperative for the mutating method and apply the “ed” or “ing” suffix > to name its non-mutating counterpart. > > | Mutating | Non-mutating | > |:------------- |:-------------------- | > | x.sort() | z = x.sorted() | > | x.append(y) | z = x.appending(y) | > > - When the operation is naturally described by a noun, use the noun for > the non-mutating method and apply the “form” prefix to name its > mutating counterpart. > > | Non-mutating | Mutating | > |:-------------------- |:--------------------- | > | x = y.union(z) | y.formUnion(z) | > | j = c.successor(i) | c.formSuccessor(&i) |

Since the mutating version of the method is Add, the non-mutating version could be Added or Adding:

// Note that following the convention results in code being written as english sentences
var empty = new ImmutableList<string>();
var list1 = empty.Adding("Hello");
var list2 = list1.Adding("immutable"); // `list2` is equal to `list1` adding "immutable"
var list3 = list2.Adding("word");

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJon SkeetView Question on Stackoverflow
Solution 1 - Language AgnosticMojoFilterView Answer on Stackoverflow
Solution 2 - Language AgnosticKenView Answer on Stackoverflow
Solution 3 - Language AgnostictvanfossonView Answer on Stackoverflow
Solution 4 - Language AgnosticspoulsonView Answer on Stackoverflow
Solution 5 - Language AgnosticLarryFView Answer on Stackoverflow
Solution 6 - Language AgnosticJaredParView Answer on Stackoverflow
Solution 7 - Language AgnosticBill the LizardView Answer on Stackoverflow
Solution 8 - Language AgnosticMichael MyersView Answer on Stackoverflow
Solution 9 - Language AgnosticTamas CzinegeView Answer on Stackoverflow
Solution 10 - Language AgnosticgnoviceView Answer on Stackoverflow
Solution 11 - Language AgnosticCraig GidneyView Answer on Stackoverflow
Solution 12 - Language AgnosticykaganovichView Answer on Stackoverflow
Solution 13 - Language AgnosticykaganovichView Answer on Stackoverflow
Solution 14 - Language AgnosticJordãoView Answer on Stackoverflow
Solution 15 - Language AgnosticChris ShafferView Answer on Stackoverflow
Solution 16 - Language AgnosticTundeyView Answer on Stackoverflow
Solution 17 - Language AgnosticchaosView Answer on Stackoverflow
Solution 18 - Language AgnosticAdam BellaireView Answer on Stackoverflow
Solution 19 - Language AgnosticPaul BrinkleyView Answer on Stackoverflow
Solution 20 - Language AgnosticWebjediView Answer on Stackoverflow
Solution 21 - Language AgnosticWedgeView Answer on Stackoverflow
Solution 22 - Language AgnostickubiView Answer on Stackoverflow
Solution 23 - Language AgnosticDavid MortonView Answer on Stackoverflow
Solution 24 - Language AgnosticJohannes Schaub - litbView Answer on Stackoverflow
Solution 25 - Language Agnosticjason saldoView Answer on Stackoverflow
Solution 26 - Language AgnosticSam HaslerView Answer on Stackoverflow
Solution 27 - Language AgnosticLBushkinView Answer on Stackoverflow
Solution 28 - Language AgnosticChrisWView Answer on Stackoverflow
Solution 29 - Language AgnosticakuhnView Answer on Stackoverflow
Solution 30 - Language AgnosticJoan VengeView Answer on Stackoverflow
Solution 31 - Language AgnosticJordãoView Answer on Stackoverflow
Solution 32 - Language AgnosticThomas WilczynskiView Answer on Stackoverflow
Solution 33 - Language AgnosticÉric MalenfantView Answer on Stackoverflow
Solution 34 - Language AgnosticBriguy37View Answer on Stackoverflow
Solution 35 - Language AgnosticAugust KarlstromView Answer on Stackoverflow
Solution 36 - Language AgnosticcorsiKaView Answer on Stackoverflow
Solution 37 - Language AgnosticPacerierView Answer on Stackoverflow
Solution 38 - Language AgnosticJosh SmeatonView Answer on Stackoverflow
Solution 39 - Language AgnosticKitsuneYMGView Answer on Stackoverflow
Solution 40 - Language AgnosticWoot4MooView Answer on Stackoverflow
Solution 41 - Language AgnosticDon StewartView Answer on Stackoverflow
Solution 42 - Language AgnosticNickView Answer on Stackoverflow
Solution 43 - Language Agnosticuser244343View Answer on Stackoverflow
Solution 44 - Language AgnosticEmmanuel DevauxView Answer on Stackoverflow
Solution 45 - Language AgnosticAlirezaView Answer on Stackoverflow
Solution 46 - Language AgnosticcodybartfastView Answer on Stackoverflow
Solution 47 - Language AgnosticPaul TomblinView Answer on Stackoverflow
Solution 48 - Language AgnosticFranci PenovView Answer on Stackoverflow
Solution 49 - Language AgnosticnsayerView Answer on Stackoverflow
Solution 50 - Language AgnosticshsteimerView Answer on Stackoverflow
Solution 51 - Language AgnosticChris MarisicView Answer on Stackoverflow
Solution 52 - Language AgnosticmP.View Answer on Stackoverflow
Solution 53 - Language AgnosticAlex BaranoskyView Answer on Stackoverflow
Solution 54 - Language AgnosticAlex BaranoskyView Answer on Stackoverflow
Solution 55 - Language AgnosticSkip HeadView Answer on Stackoverflow
Solution 56 - Language AgnosticBenjolView Answer on Stackoverflow
Solution 57 - Language AgnosticlittlegeekView Answer on Stackoverflow
Solution 58 - Language AgnosticErich MirabalView Answer on Stackoverflow
Solution 59 - Language AgnosticErich MirabalView Answer on Stackoverflow
Solution 60 - Language AgnosticorjView Answer on Stackoverflow
Solution 61 - Language Agnosticuser1342582View Answer on Stackoverflow
Solution 62 - Language AgnosticquodlibetorView Answer on Stackoverflow
Solution 63 - Language AgnosticClaudiuView Answer on Stackoverflow
Solution 64 - Language AgnosticBubba88View Answer on Stackoverflow
Solution 65 - Language AgnosticAndrei RView Answer on Stackoverflow
Solution 66 - Language AgnosticJamesView Answer on Stackoverflow
Solution 67 - Language AgnosticpeoroView Answer on Stackoverflow
Solution 68 - Language AgnosticHeiko HatzfeldView Answer on Stackoverflow
Solution 69 - Language Agnostick reyView Answer on Stackoverflow
Solution 70 - Language AgnosticJordãoView Answer on Stackoverflow
Solution 71 - Language AgnosticAlex NorcliffeView Answer on Stackoverflow
Solution 72 - Language AgnosticJustin BreitfellerView Answer on Stackoverflow
Solution 73 - Language AgnosticPablo LozanoView Answer on Stackoverflow
Solution 74 - Language Agnosticserv-incView Answer on Stackoverflow
Solution 75 - Language AgnostickofifusView Answer on Stackoverflow
Solution 76 - Language AgnosticGabrielView Answer on Stackoverflow