views:

3940

answers:

56

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

+13  A: 

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.

JaredPar
Have added reasons for my preference for Plus over Add to the question. Would welcome comments on that reasoning. I'm *really* open to the idea that I'm being silly.
Jon Skeet
@JaredPar: What about if the type is called TestSuite though?
Jon Skeet
@Jon, response in soon to come edit
JaredPar
Would love to give another +1 for edit 3, but obviously can't. (In my case I'm not trying to get parallelism - I believe that immutability leads to code which is easier to reason about.) I'm still not *quite* convinced that Add is the way to go, but the support for in answers here is persuasive.
Jon Skeet
If you could happen to drop this question into conversation at work, that would be awesome too, btw. I started the discussion on a C# list, so some colleagues may already be involved. Might ask internally at Google too...
Jon Skeet
@Jon, I think I know a good place to drop this question at work :)
JaredPar
ocaml does the same thing for it's immutable Set library. It's fine to call it add in my opinion.
nlucaroni
+8  A: 

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

Michael Myers
Not all immutable collections require a copy to add though. Think of immutable trees, they just need a new node and can use the existing tree as a leaf.
JaredPar
BTW, I read your profile, then age in order and was briefly amazed at how old you were. Sanity kicked in shortly thereafter.
JaredPar
Re first comment: I use trees so rarely that that thought never occurred to me. That is a good point.
Michael Myers
Re second comment: I confess, I did it for the badge! I just don't like to give out my age. (I'm actually younger than you, but I can play the crotchety old-timer pretty well if I need to. And I'm not the only one whose age is listed as 89.)
Michael Myers
@mmyers, you're assuming that I didn't lie on my profile :)
JaredPar
No, i didn't lie. My age is correct
JaredPar
Who would pick 28 anyway? :)
Michael Myers
A: 

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.

it depends
+3  A: 

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

Tundey
I'd argue that DateTime.Add has been known to confuse people... but I agree it shows precedence.
Jon Skeet
Just like methods to mutate a string are confusing to new developers. But soon enough everybody learns that "strings are immutable"
Tundey
+4  A: 

A few random thoughts:

  • ImmutableAdd()
  • Append()
  • ImmutableList<T>(ImmutableList<T> originalList, T newItem) Constructor
Chris Shaffer
+1 for ImmutableAdd; not keen on Append (too much like StringBuilder.Append which is mutating) and the constructor version is a pain in terms of chaining.
Jon Skeet
+3  A: 

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

David Morton
It's no list, it's a test suite.
tstenner
A: 

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

Paul Tomblin
If I see foo.Replace(), I'm going to think that foo is getting replaced.
chaos
Yes, because it is. Whereas when I see foo.add(), I'm going to think that something is going to get added to foo, which it isn't in this case.
Paul Tomblin
Usually, replace() takes 2 arguments, something to replace, and something to replace it with. Not sure how clear it would be to see a replace method that does something different...
Outlaw Programmer
+4  A: 

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.

DrJokepu
Still kinda implies doing something to the base object.
chaos
A: 

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.

Franci Penov
A: 

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");
}
ChrisW
Like the DateTime argument earlier, I'd agree with the precedence if it weren't for the fact that so many programmers *do* expect string methods to do stuff. They have to be told (sometimes repeatedly) that strings are immutable. I'd like to lure my client developers into the pit of success :)
Jon Skeet
+4  A: 

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.

gnovice
A: 

How about "Augment"?

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

nsayer
It's still a verb which sounds like it's doing something *do* its target.
Jon Skeet
+3  A: 

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

chaos
+27  A: 

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");
tvanfosson
I like the Empty idea. Still not convinced about And though. It's just a bit blah.
Jon Skeet
It just seems more like how I would think about constructing a list of things in natural language. If you read it out loud it seems more intuitive than Add or Plus. "list" is the empty list and "Hello" and "Immutable" and "Word". I would agree that it's less clear in isolation, though.
tvanfosson
A: 

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

shsteimer
+2  A: 

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

Adam Bellaire
+19  A: 

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.

spoulson
I kind of like 'Join' also but it, in most cases, when you join 2 objects, you end up with 1. In this case, if you join 2 objects, you're actually creating a new object.
Outlaw Programmer
I don't know of any cases in .NET, Perl, PHP, or even VBScript where Join implies mutation. The design is such that A and B joins to make C, where C is always a new entity.
spoulson
I like Join, and I totally agree with thesaurus.com :) Use it all the time when in doubt about a name.
Skurmedel
var suite = new TestSuite<string, int>().Join(x => x.Length);
Sly
I see your point, but be careful with this: http://mindprod.com/jgloss/unmainnaming.html (no. 6)
Marc Wittke
+16  A: 

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");
LarryF
+1. "WITH" is an infix operator in SETL that does the same thing. If SETL uses it then it must be right :-)
finnw
+1; this might be confusing in vb, though
Michael Haren
Bah... Who uses VB anymore? :) Uh.. Opps.. Was that out loud? heh.. But, no, in all seriousness, that's why I considered the "AlongWith", that would remove the VB issue. There are only about a million different ways he could go with this one... I mean, even insane ones like: object.Plus(), or Object.ExistingPlus()... etc... It's a damn good question he posted, however... heh..
LarryF
+47  A: 

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

Ken
Don't forget that discoverability is important though - if I type "testSuite." and look at the list of methods, I would like to see a method which suggests the right thing. I probably won't look up a nonsensical (to me) name on the offchance it's what I want.
Jon Skeet
+1 for nice explanation of your reasoning though.
Jon Skeet
If I was feeling snarky, I'd make a method Add which simply threw an exception with message="Use Cons to prepend to an ImmutableList". :-)
Ken
John R. Strohm
Traditionally, cons adds at the beginning rather than the end. So it is a potentially misleading name for the method described.
walkytalky
Just to save the the next non-functional programmer a click or 3... http://en.wikipedia.org/wiki/Cons from the word "construct", the expression "to cons x onto y" means to construct a new object with (cons x y)
Myster
Seeing as Cons means Construct, and the implementation is just going to directly call a constructor in 99% of cases, I'd skip the Cons method entirely and just use the constructor.
Joren
+1  A: 

.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");
Chris Marisic
+1  A: 

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

Johannes Schaub - litb
But a copy is not always necessary in an immutable collection. Take a binary tree for instance. Adding a new root requires no copying, just a new value where one of the leafs is the old tree
JaredPar
KISS - If naming started to include implementation details all method names would become overly long. "add" is simple enough and does the job.
mP
@mP: Again you use the phrase "implementation detail" in a way which I believe is unsuitable. Whether it's a linked list or an array under the hood is an *implementation* detail. I could change the *implementation* without changing the API. The immutable aspect is *not* an implementation detail.
Jon Skeet
right. JaredPar, but i think it's also not important whether it *actually* copies the tree or just uses the existing tree and use it as a leaf for the new tree returned. i mean, *that* is just an implementation detail. it's the same for (i believe) the substring operation for java's string class.
Johannes Schaub - litb
A: 

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

mP
a) String confuses people; b) the signature doesn't reveal the non-mutation: see StringBuilder.Append. The point is that the method *doesn't* add a new element to *this* list; it creates a *new* list with the extra element. I don't believe that "Add" makes that clear.
Jon Skeet
I also dispute the idea that it's an "implementation detail". To me, an implementation detail is something one can largely ignore - here, if you ignore it and assume it works like a mutable list, you'll almost certainly get it wrong.
Jon Skeet
(I don't want to sound ungrateful just because I disagree, btw - thanks very much for the answer!)
Jon Skeet
The fact that it returns a new list is the entire point. If you mutate, then "b = a.Add(x);" may not even compile, and the correct code is just "a.Add(x);". If you don't mutate then "a.Add(x);" will still compile, but in fact is just a no-op.
Wedge
@JonDevelopers need to have some level of competance and *understand* what happens for so called mutator methods on immutable classes.Given that we know String is immutable then it becomes obvious that any mutator methods return new Strings ...
mP
@JonAre you saying the Dot.net + Java lib designers gave bad names ?Are you saying the Dot.net guys made the same mistake as the Java guys - i dont think so.I would disagree the names are concise and anyone with some level of competance understands what happens.
mP
@WedgeIts not a nop - something does happen - the new list is still created - the problem is your code doesnt use the new list.Method names should describe what they generally do. You cant put the entire lifes story in the method name - eg StringBuilder.append() its not appendReturnsNewSB.
mP
Sorry with the last line - its a bit mixed up - should sayString.appendReturnsSameStringBuilderNotANewCopy().
mP
@WedgeGo scan/read the javadoc apis (im sure the same will be true of dotnet) and you will notice that they never include "immutable" in any method name - even for immutable classes.Method names should be simple words or identifiers of the action.
mP
@WedgeIt would be impractical for methods to have all the important details of what happens. There are many examples in java/dotnet that illustrate this.
mP
@mP: I'm saying that lots of people are thrown by the fact that strings are immutable. For core types that's not too bad - anyone with a question will get an answer very quickly. For my framework, I doubt there'll be as many people ready to help :) I want to make the barrier to entry *very* low.
Jon Skeet
@Jon: Ultimately any users of any framework needs to spend a minute or two when using any class for the first time. The preamble dutifully should describe how and what the class does. Otherwise how will discover your class to begin with. Whilst they are add it they may as well read the doco.
mP
+32  A: 

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);
MojoFilter
This is what I use, because it's what System.Linq.Enumerable uses - the decision is already made. :) I can't be the only person who has defined his own overload of the Concat extension on IEnumerable to accept a single value to be appended.
Daniel Earwicker
+1 This is *the* correct answer for maintaining naming consistency within the framework.
280Z28
+10  A: 

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

Bill the Lizard
What if you have a generic list, to which you could legitimately add an integer (say) *or* another list of integers? Then this use of + will conflict with concatenation.
finnw
@finnw: I don't see your point. With a list I would always expect + to mean append, whether you're adding one element or many.
Bill the Lizard
For a reusable API, it's a good idea to also have a named method, in case someone is using your class from a language without operator overloading.
Neil Whitaker
@Bill: "whether you're adding one element or many" -- what if you want to add the list as a single element? i.e., `[1] + 2 = [1,2]` but `[1] + [2] = [1,[2]]`. What you're suggesting is inconsistent behavior. This is probably why Python doesn't allow you to add *one* element in this fashion.
Mark
+3  A: 

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.

Paul Brinkley
+2  A: 

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

Strilanc
+2  A: 

How about Chain() or Attach()?

Webjedi
A: 

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);
Éric Malenfant
+2  A: 

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.

jms
+1 for Union. I, however, borrow it directly from set theory. :-)
Lette
Doesn't SQL get much of its terminology from set theory?
Jason D
Also, Union implies distinction .. If you want to include duplicates (at least in TSQL), you have to use Union All explicitly.
hemp
+4  A: 

Join seems appropriate.

ykaganovich
+4  A: 

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

ykaganovich
+1  A: 

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

Alex Baranosky
So you suggest prefixing all other methods from the List which return a new list with "immutable" ?So we have immutableAdd(), immutableGet(), immutableIterator() etc ?
mP
I'd argue that ImmutableAdd isn't simple *enough* - in that when you've got a bunch of calls to it, it clutters things up too much. I'd prefer a single word. Yes, I know I'm being very picky :)
Jon Skeet
just a suggestion :)
Alex Baranosky
+2  A: 

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

Wedge
+2  A: 

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.

Sam Hasler
A: 

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

Or "Attach" or "AttachTo".

Alex Baranosky
A: 

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

Skip Head
As I commented elsewhere, that sucks in terms of chaining calls together unfortunately :( I'll definitely include a constructor form which takes an IEnumerable<...> though.
Jon Skeet
+2  A: 

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.

Adrian
A: 

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

Benjol
A: 

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);
+1  A: 

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.

Josh Smeaton
Hmmm... I don't think that if I saw "GetWith" I'd know what it meant without looking it up (let alone being discoverable). Your reasoning about Plus is interesting, although there's precedent with things like DateTime + TimeSpan which I've never had any trouble with.
Jon Skeet
A: 

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.
Erich Mirabal
A: 

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.

Erich Mirabal
Multiple answers is fine by me :) I'm not sure that extension methods are sufficiently obviously extension methods to give the right impression though.
Jon Skeet
Just throwing some ideas out there that haven't been expressed. I still prefer `Freeze` (or some variation of that). Is `Plus` still your current choice?
Erich Mirabal
+1  A: 

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.

Joan Venge
Yes, I see your point. I think I still prefer Plus, but it's a point worth considering.
Jon Skeet
Thanks Jon. I am looking forward to using your framework. I just read about it and it looks very good. Thanks again.
Joan Venge
+2  A: 

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.

LBushkin
A: 

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

orj
A: 

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

jeyoung
Maybe... not terribly convinced.
Jon Skeet
augment sounds cool, it accents the immutability
Bubba88
A: 

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.

quodlibetor
I can't say I'm a big fan - I don't think I'd really know what it was meant to do without looking it up. Keep 'em coming though :)
Jon Skeet
huh, I've liked this one... for first 15 seconds)
Bubba88
+3  A: 

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())
);
Jordão
@Jordao: Because this sort of composition leads to a much simpler initalization form. Why have two separate variables when I only want one? Likewise I don't want to create a mutable copy - I want everything to be immutable throughout, as that leads to code which is easier to reason about, IMO.
Jon Skeet
I've changed my answer accordingly...
Jordão
All of these are still rather more unwieldy than "Plus" etc. Thanks for the ideas involving mutation, but I definitely prefer the "keeping it immutable" approach.
Jon Skeet
Maybe then there'll always be misinterpretations on what the real semantics of the operation are. If you follow the specification object route, there's no mutation going on (at least not externally), the object only specifies what the new immutable object will look like. What you have is an operation that goes from one immutable object to another, and since it's called Copy, there's no room to misunderstandings.
Jordão
The only names that would work for you seem to be compound names, like CopyAndAppend, CopyAndAdd, etc.
Jordão
I actually am growing fonder of this approach (with all the edits) as an API for immutable collections. However, I would argue that combining this approach with *helper* methods for default specifications, such as Concat, offers the best of both worlds.
hemp
I guess this specification object is a specialized form of the builder pattern. I've also got many of these ideas from the StructureMap DI container design. It tries to drive the API user to do the right thing, without the possibility of misinterpretation. And yes, helper methods are essential to accomplish common tasks effortlessly.
Jordão
A: 

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

Claudiu
A: 

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.

kubi
A: 

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)

KitsuneYMG
A: 

list.copyAndAppend(elt)

How does that sound?)

Bubba88
A: 

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.

Andrei Railean
@Andrei: No, I'm afraid I disagree. Switching between mutable and immutable states ends up being much harder to understand. Operations like this are a core part of functional programming - the idea of "create a new list which has the contents of the old list but with this new item as well" isn't really "two things at once" IMO.
Jon Skeet
A: 

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");
James
Passing an argument to a clone method looks pretty odd to me.
Jon Skeet
A: 

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.

Jordão
A: 

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

Thomas Wilczynski