234

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

BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • I think there would be no ambiguity to "Add" assuming the class doesn't support both mutating and non-mutating operations. If it did, I could see wanting to be more specific. – J Cooper Feb 06 '09 at 20:01
  • The problem isn't the name, it's that C# automatically ignores the return value. So, coming up with creative names won't solve the underlying problem that most types in C# are mutable. Not to mention getting good names like Plus for other cases (Insert, Remove, Push, Pop, etc..) – MichaelGG Feb 06 '09 at 20:13
  • also, you're not abusing type infererence enough. From BclExtras. var list = ImmutableList.CreateFromArguments("foo"); – JaredPar Feb 06 '09 at 20:27
  • At the beginning of Edit 1, do you mean "the former is clearly buggy", meaning Add rather than Plus? – Adam Bellaire Feb 06 '09 at 20:30
  • 2
    @Adam: No, the latter is clearly buggy. They're both *actually* buggy (as they're doing nothing with the result) - but the first doesn't *look* buggy to me. – Jon Skeet Feb 06 '09 at 20:35
  • @litb: Interesting idea. Suffers from the abbreviation problem, but interesting, certainly... – Jon Skeet Feb 06 '09 at 20:53
  • 1
    i deleted what i suggested :) well it was "Concat". but there is no "Remove" equivalent to it though :/ – Johannes Schaub - litb Feb 06 '09 at 20:55
  • 1
    @Jon, "Uncat" sounds let a pet problem ;) – JaredPar Feb 06 '09 at 21:10
  • 36
    Is an uncat a dog? – Michael Myers Feb 06 '09 at 21:15
  • 7
    Concat/Condog... works for me! ;) – gnovice Feb 06 '09 at 21:16
  • 11
    Uncat - that'd be a zombie cat. – Erik Forbes Feb 07 '09 at 00:22
  • I'd suggest picking the top 5 (or fewer) options and creating individual posts that people can vote up / down. – Wedge Feb 07 '09 at 00:33
  • I would remove the bit its not obvious that the list is actually immutable. What ever happened to people actually reading the documentation to learn what a class actually does. – mP. Feb 07 '09 at 07:47
  • @mP: In this case I have a strong motivation to make the barrier to entry as low as humanly possible. See http://msmvps.com/blogs/jon_skeet/archive/2009/02/02/benchmarking-designing-an-api-with-unusual-goals.aspx – Jon Skeet Feb 07 '09 at 08:11
  • I definitely like Plus over Add. – Alex Baranosky Feb 08 '09 at 14:53
  • public *static* T Add( T a, T b ) – Trap Mar 09 '09 at 14:27
  • 2
    @Trap: That sucks in terms of making the API fluid though. – Jon Skeet Mar 09 '09 at 15:02
  • added answer - just in case you havent see it - thought would use the comments to hightlight this too you. –  Mar 13 '09 at 09:33
  • @littlegeek: I saw it. It's okay, but I think I prefer "Plus" at the moment. – Jon Skeet Mar 13 '09 at 09:41
  • "cons" is only familiar to Lisp people, not all functional programming people. – ShreevatsaR Apr 16 '09 at 02:36
  • Did you ever arrive at a conclusion? – Erik Forbes Jun 11 '09 at 22:34
  • @Erik: Not really. I think Plus is my favourite at the moment. Unfortunately I don't have time to work on the project at the moment :( – Jon Skeet Jun 11 '09 at 22:36
  • "With: ... doesn't have quite the same 'additionness' to it" -- Isn't that a good thing? You are specifically *not* adding an element to an existing collection, you are asking what the resulting collection would look like. – finnw Jun 26 '09 at 12:50
  • @finnw: I expressed my point badly - "with" makes it sound (to me) like you're *replacing* a value rather than *adding* one (in the new object). "WithExtraTest" or something similar might work, but it's a bit wordy. – Jon Skeet Jun 26 '09 at 13:34
  • At the risk of a little verbosity, perhaps something like: RebuildWith(), RecreateWith() or RemakeWith() – steamer25 Nov 03 '09 at 23:55
  • I'm definately late to the party here... but how about .Include()? – Scott Nov 24 '10 at 15:35
  • When talking about not wanting to use the operator overload, you mention that it should be reserved for lower-level types. Why is that true? I think you like .Plus the best because EVERYONE knows that A+B doesn't mutate anything. – Neal Tibrewala Mar 01 '11 at 06:53
  • @Neal: It's more of a gut feeling than anything else, but it would just *feel* wrong somehow... – Jon Skeet Mar 01 '11 at 07:00
  • On the plus side, I abandoned Lists for Enumerables long ago, so now I'm surprised when ANYTHING causes mutation. Yay C# going functional! – Neal Tibrewala Mar 01 '11 at 08:21
  • Off topic, but have you done any blog posts about the advantages/disadvantages of immutable lists? I've been reading Eric Lippert's series on immutability lately, but I haven't seen that particular topic addressed. – Justin Morgan - On strike Sep 23 '11 at 18:50
  • @JustinMorgan: Nope, I haven't I'm afraid. – Jon Skeet Sep 23 '11 at 18:53
  • Just out of curiosity, which method name did you choose? IMO Add is definitely a bad choice too since if `ImmutableClass : IEnumerable` `new ImmutableClass { someElement }` looks reasonable, but is even tougher to spot that the collection initialiser does nothing. – Rich O'Kelly Jan 26 '12 at 11:55
  • @rich.okelly: I can't remember - I haven't looked at that project for quite a while :) (I must get back to it some time...) – Jon Skeet Jan 26 '12 at 11:55
  • `plus` and `minus` I would expect to take the same type twice. After all you do `"abc"+"d"`, not `"abc"+'d'`. – Thomas Ahle Feb 14 '12 at 00:31
  • @ThomasAhle: Not sure what you mean there - in plenty of languages "abc" + 'd' is absolutely valid; likewise `DateTime.Now + TimeSpan.FromMinutes(10)` is valid in C#... – Jon Skeet Feb 14 '12 at 06:23
  • @JonSkeet: Being a non C# person, that sort of makes sense from a timestamp perspective. Using plus with different types, makes you wonder which of the types are used for the result. At least a plus should be associative and have closure, imho. – Thomas Ahle Feb 16 '12 at 03:22
  • @ThomasAhle: But `TimeSpan` and `DateTime` are already different types... I use it in Noda Time as well for daylight saving offsets; it's really handy: Instant + Offset = LocalInstant; LocalInstant - Offset = Instant. It means you can't use it the wrong way round, which is lovely... – Jon Skeet Feb 16 '12 at 08:01
  • This is already solved(sort of) by Enumerable.Concat. Create your own extension Concat(this IEnumerable, T second) – csauve May 30 '12 at 04:48
  • @csauve: Concat concatenates two *sequences*, not concatenating a single element onto a sequence. Additionally, even "Concat" is far from clear IMO. It's an abbreviation, and one from a word which is very rarely used in English. – Jon Skeet May 30 '12 at 05:42
  • I see what you mean - intuitively I think of .Concat(t) as really just an abbr for .Concat(new[] {t}), which as you say is an abbr for .Concatenate(new[] {t}). We still use it in our codebase, as well as a similar overload for .Union(T) (for enforcing uniqueness). Alternatively if you don't mind writing out .Concat(new[] {t}) you can actually just use that extension method and you don't need to modify your class at all. – csauve May 30 '12 at 14:59
  • 2
    Clojure uses 'conj' for conjoin. Kinda like 'cons' but the behavior is polymorphic to the collection. – gtrak Dec 01 '12 at 16:44
  • Another reason to avoid `Add` is that it gives you collection initializer syntax. `new ImmutableCollection { a, b, c }` is pointless and serves no purpose. – nawfal Nov 09 '13 at 14:03
  • @nawfal: Yes - it's a real shame that collection initializer syntax doesn't support immutable collections (via using the return value). – Jon Skeet Nov 09 '13 at 15:50
  • @JonSkeet Yes, I'm with you on that part. The closest you get is with `params` keyword in the constructor for single values, like `new ImmutableCollection(a, b, c)`... – nawfal Nov 09 '13 at 17:16
  • @JonSkeet is your `ImmutableList` source available? Is it part of some library? Would love to see :) – nawfal Nov 12 '13 at 08:49
  • @nawfal: I don't actually have such a thing - but of course the Microsoft immutable collections are now available anyway :) – Jon Skeet Nov 12 '13 at 08:55
  • @JonSkeet oh yes I missed that! – nawfal Nov 12 '13 at 09:52
  • @rezomegreldize: That sounds like it's going to modify the original collection though :( – Jon Skeet Jan 23 '14 at 22:16
  • Since nobody's mentioned Python: in Python, tuples are immutable, and they refer to this operation as "concatenate", e.g. with `a=(1,2)` you can append an element with `a=a+(3,)`. The inverse (removing an item from a list) is called "slicing", e.g `a=a[:-1]`. Even list concatenation returns a new list. So this is a language feature expected by experienced Python programmers. There are also [named tuples](http://docs.python.org/2/library/collections.html#collections.namedtuple), but these have no method naming conventions. – cod3monk3y Jan 28 '14 at 20:16

76 Answers76

132

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
  • 12,256
  • 14
  • 53
  • 61
  • 3
    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 Jun 23 '09 at 20:04
  • 9
    +1 This is *the* correct answer for maintaining naming consistency within the framework. – Sam Harwell Feb 07 '10 at 18:23
  • Unless I'm missing it, System.Linq.Enumerable (and Linq in general) only uses Concat() for "sequence + sequence", never "item + sequence". The problem that someone "might expect it to add two lists together rather than adding a single value to the other list" was explicitly given as a reason not to use one of the other original options. – Ssswift Jan 11 '18 at 01:14
119

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
  • 5,074
  • 6
  • 30
  • 26
  • 16
    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 Feb 06 '09 at 21:09
  • 33
    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 Feb 09 '09 at 18:12
  • 2
    It won't kill anyone to read a few lines of comments explaining why the name is what it is, and referring them to, say, Abelson & Sussman's "Structure and Interpretation of Computer Programs". – John R. Strohm Feb 07 '10 at 16:25
  • 16
    Traditionally, cons adds at the beginning rather than the end. So it is a potentially misleading name for the method described. – walkytalky Apr 23 '10 at 15:02
  • 16
    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 May 26 '10 at 23:17
  • 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 Sep 17 '10 at 01:53
  • 1
    @Joren that's not going to give the user a defined behavior though. `MyImmutableThing(oldThing,smallAddition)` doesn't make for a very intuitive constructor. – corsiKa Jun 22 '11 at 20:22
  • Cons is most often used for lists. As I read OP, the name should also work for trees and sets. – Thomas Ahle Dec 23 '11 at 22:54
  • @walkytalky I've seen snoc used for appending (eg that's what Okasaki does) – dubiousjim May 31 '12 at 13:26
59

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
  • 524,688
  • 99
  • 697
  • 795
  • I like the Empty idea. Still not convinced about And though. It's just a bit blah. – Jon Skeet Feb 06 '09 at 20:15
  • 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 Feb 06 '09 at 20:19
52

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.

Community
  • 1
  • 1
spoulson
  • 21,335
  • 15
  • 77
  • 102
48

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
  • 4,925
  • 4
  • 32
  • 40
  • +1. "WITH" is an infix operator in SETL that does the same thing. If SETL uses it then it must be right :-) – finnw Jun 26 '09 at 12:51
  • 1
    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 Nov 24 '09 at 03:24
35

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
  • 733,204
  • 149
  • 1,241
  • 1,454
  • 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 Feb 06 '09 at 20:02
  • @JaredPar: What about if the type is called TestSuite though? – Jon Skeet Feb 06 '09 at 20:39
  • 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 Feb 06 '09 at 21:01
  • 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 Feb 06 '09 at 21:02
  • @Jon, I think I know a good place to drop this question at work :) – JaredPar Feb 06 '09 at 21:03
  • ocaml does the same thing for it's immutable Set library. It's fine to call it add in my opinion. – nlucaroni Feb 06 '09 at 21:38
27

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
  • 398,270
  • 210
  • 566
  • 880
  • 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 Jun 26 '09 at 12:53
  • @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 Jun 26 '09 at 12:59
  • 4
    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 Dec 22 '09 at 20:50
  • "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. – mpen Aug 07 '10 at 01:29
  • Well, in a statically typed language like C# you can tell what the type of list elements is, whether a list of lists or a list of elements, so you can use the type to decide whether to add one element that is a list or concatenate the two lists. – Dobes Vandermeer May 18 '14 at 05:28
22

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

Michael Myers
  • 188,989
  • 46
  • 291
  • 292
  • 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 Feb 06 '09 at 21:40
  • BTW, I read your profile, then age in order and was briefly amazed at how old you were. Sanity kicked in shortly thereafter. – JaredPar Feb 06 '09 at 21:42
  • Re first comment: I use trees so rarely that that thought never occurred to me. That is a good point. – Michael Myers Feb 06 '09 at 22:03
  • 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 Feb 06 '09 at 22:07
  • The immutable trees argument is a strong one, good point. So then EquivalentReferenceWithAdded (x) would fight that argument, but sounds stupid, and hard to deduce. – TheBlastOne Aug 10 '11 at 22:43
21

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.

Tamas Czinege
  • 118,853
  • 40
  • 150
  • 176
18

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
  • 125,304
  • 15
  • 256
  • 359
18

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

Craig Gidney
  • 17,763
  • 5
  • 68
  • 136
  • 1
    Python also uses this convention. E.g. built-in functions reversed() and sorted(). – Joe Dec 27 '10 at 04:17
14

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
  • 14,736
  • 8
  • 59
  • 96
  • +1. this is not enforced by the language, but agreed upon as a convention. I like that. – oma May 17 '11 at 18:27
13

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
  • 55,340
  • 13
  • 112
  • 144
  • @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 Feb 07 '10 at 08:31
  • 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 Feb 09 '10 at 14:14
  • 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 Feb 09 '10 at 15:23
  • The only names that would work for you seem to be compound names, like CopyAndAppend, CopyAndAdd, etc. – Jordão Feb 09 '10 at 15:32
  • 1
    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 Jun 04 '10 at 18:11
  • 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 Jun 04 '10 at 18:46
13

Join seems appropriate.

ykaganovich
  • 14,736
  • 8
  • 59
  • 96
11

A few random thoughts:

  • ImmutableAdd()
  • Append()
  • ImmutableList<T>(ImmutableList<T> originalList, T newItem) Constructor
Chris Shaffer
  • 32,199
  • 5
  • 49
  • 61
  • 1
    +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 Feb 06 '09 at 19:58
10

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
  • 2,926
  • 1
  • 23
  • 27
  • I'd argue that DateTime.Add has been known to confuse people... but I agree it shows precedence. – Jon Skeet Feb 06 '09 at 19:58
  • 1
    Just like methods to mutate a string are confusing to new developers. But soon enough everybody learns that "strings are immutable" – Tundey Feb 06 '09 at 20:59
9

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
  • 122,029
  • 33
  • 303
  • 309
9

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
  • 108,003
  • 19
  • 148
  • 163
9

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
  • 6,283
  • 3
  • 24
  • 33
8

How about Chain() or Attach()?

Webjedi
  • 4,677
  • 7
  • 42
  • 59
  • 1
    Attach surely sounds like being mutating. Maybe WithAttached would be wiser, but is very close to WithAdded, which has been discussed above. – TheBlastOne Aug 10 '11 at 22:46
  • It's funny how many times "chaining" is mentioned in describing what is trying to be done with this. (5 times), but not offered as a suggestion! It's the first thing that came up on `visualthesaurus.com` (no affiliation) when I searched for `concatenate`. – cod3monk3y Jan 28 '14 at 20:27
7

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
  • 19,513
  • 7
  • 48
  • 71
6

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
  • 48,104
  • 19
  • 94
  • 118
  • +1 the `[object]By[Verb]ing[Object]:` prefix to the method implies that a new string will be returned as opposed to simply `[verb][Object]:`, which would mutate the object in-place. – Dave DeLong Mar 25 '11 at 23:35
  • 3
    +1. I don't understand people's aversion to verbosity (aka self-documentation). – hatfinch Jul 19 '11 at 23:00
6

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.

jason saldo
  • 9,804
  • 5
  • 34
  • 41
5

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

David Morton
  • 16,338
  • 3
  • 63
  • 73
5

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
  • 496,577
  • 130
  • 894
  • 1,212
  • 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 Feb 06 '09 at 21:21
  • KISS - If naming started to include implementation details all method names would become overly long. "add" is simple enough and does the job. – mP. Feb 07 '09 at 07:42
  • 1
    @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 Feb 08 '09 at 20:22
  • 1
    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 Feb 08 '09 at 20:50
5

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
  • 12,344
  • 10
  • 72
  • 106
5

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
  • 129,300
  • 32
  • 216
  • 265
4

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
  • 54,973
  • 13
  • 116
  • 224
  • 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 Feb 06 '09 at 20:03
  • I like Append more and more. It distinguishes that you are not mutating the collection but joining to it. –  Feb 04 '11 at 21:06
4

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.

akuhn
  • 27,477
  • 2
  • 76
  • 91
3

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
  • 55,340
  • 13
  • 112
  • 144
3

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

Christian Specht
  • 35,843
  • 15
  • 128
  • 182
3

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
  • 315,713
  • 212
  • 479
  • 689
2

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
  • 13,938
  • 1
  • 40
  • 42
2

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");
Briguy37
  • 8,342
  • 3
  • 33
  • 53
  • I like the notion of "clone" to express the idea of the immutability conservation but "with" is a bit ambiguous in this current context. – Emmanuel Devaux Aug 26 '11 at 07:58
  • @Emmanuel Devaux: Thanks for the input, but will you please clarify what you mean when you say "'with' is a bit ambiguous in this current context"? For example, what else would `[1,2].cloneWith(3)` logically be other than the new array `[1,2,3]`? – Briguy37 Aug 26 '11 at 14:24
  • "With" do not express what is the final action (add , remove etc...) "With" suggest that parameter is self explanatory to know the final action ...ex: cloneWith("Hello") ... will it be add or just taken as a filter like "clone this object with hello as filter"... "With" synonym of "tied to" / "has" / "match"... – Emmanuel Devaux Aug 26 '11 at 14:38
  • @Emmanuel Defaux: Thanks for the clarification. I would not normally think of `cloneWith(x)` as applying a filter unless it was `cloneWithFilter(x)`, so thank you for the different point of view. – Briguy37 Aug 26 '11 at 15:25
2

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");
August Karlstrom
  • 10,773
  • 7
  • 38
  • 60
2

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?
corsiKa
  • 81,495
  • 25
  • 153
  • 204
  • Some types of immutable collection support reasonably-efficient means of appending items. – supercat Jan 28 '12 at 06:59
  • @supercat Perhaps you could elaborate on what you mean by reasonably efficient. Typically an immutable collection has to make a copy of the backing data. – corsiKa Jan 28 '12 at 07:14
  • As a best-case example, consider an immutable stack type implemented as a linked list. Given an existing stack, one can make a stack with one more element pushed on by creating a new element linked to the old stack and then returning that element. One can make a stack with one fewer element pushed on by simply returning the 'next' pointer of the first element. – supercat Jan 28 '12 at 15:32
  • @supercat I edited my answer to illustrate an example of why that wouldn't work. – corsiKa Jan 28 '12 at 20:32
  • This is exactly what I suggested one down from you. – Justin Breitfeller May 24 '12 at 17:04
2

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

Pacerier
  • 86,231
  • 106
  • 366
  • 634
1

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
  • 12,753
  • 4
  • 37
  • 58
1

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.

Alireza
  • 5,421
  • 5
  • 34
  • 67
1

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

Woot4Moo
  • 23,987
  • 16
  • 94
  • 151
1

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.

Don Stewart
  • 137,316
  • 36
  • 365
  • 468
  • 1
    Concat works for me, but for some reason Append sounds more like a mutating operation. (Obviously not a problem in a functional environment where nothing mutates.) – Jon Skeet May 20 '11 at 07:04
1

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.
Nick
  • 5,765
  • 5
  • 27
  • 36
1

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

1

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
  • 47,939
  • 24
  • 129
  • 164
  • 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 Apr 04 '09 at 07:17
1

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

Emmanuel Devaux
  • 3,327
  • 4
  • 25
  • 30
0

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
  • 13,234
  • 14
  • 63
  • 73
0

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

0

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
  • 8,185
  • 4
  • 35
  • 48
0

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
  • 224,032
  • 165
  • 485
  • 680
0

list.copyAndAppend(elt)

How does that sound?)

Bubba88
  • 1,910
  • 20
  • 44
0

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.

Pablo Lozano
  • 10,122
  • 2
  • 38
  • 59
0

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 R
  • 4,904
  • 5
  • 25
  • 26
  • @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 Apr 25 '10 at 08:01
0

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
  • 80,725
  • 18
  • 167
  • 237
0

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

serv-inc
  • 35,772
  • 9
  • 166
  • 188
0

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.

peoro
  • 25,562
  • 20
  • 98
  • 150
  • I can see the verb working when there are no parameters, but using `Added(extraTest)` sounds odd to me. But this question shows just how subjective it all is :) – Jon Skeet Nov 22 '10 at 13:59
0

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.

Heiko Hatzfeld
  • 3,197
  • 18
  • 15
0

Borrowing from C, how about Concat

k rey
  • 611
  • 4
  • 11
0

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");
Jordão
  • 55,340
  • 13
  • 112
  • 144
  • 1
    Unfortunately that makes it a complete pain to use in a fluent way :( – Jon Skeet Mar 03 '11 at 15:09
  • I agree, that's why I've added the `params` parameter as a mitigation strategy for the "chaining" usage. But that only works if you're "chaining" `Add`s :-( – Jordão Mar 03 '11 at 15:11
  • You can also return the newList as well, ala [`strcpy`](http://www.cplusplus.com/reference/clibrary/cstring/strcpy/). – Jordão Mar 03 '11 at 15:33
  • I think the `ref` approach is sometimes under-appreciated. While it is often useful to have a function-style alternative to allow for cases where one may not wish to modify the storage location which holds the original reference, I think the `ref` approach is clearer in cases where the same storage location will be source and destination. – supercat Jun 09 '12 at 20:41
0

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.

codybartfast
  • 7,323
  • 3
  • 21
  • 25
0

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

Paul Tomblin
  • 179,021
  • 58
  • 319
  • 408
  • If I see foo.Replace(), I'm going to think that foo is getting replaced. – chaos Feb 06 '09 at 20:47
  • 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 Feb 06 '09 at 20:53
  • 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... – Tim Frey Feb 06 '09 at 21:48
0

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
  • 74,861
  • 18
  • 132
  • 169
0

How about "Augment"?

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

nsayer
  • 16,925
  • 3
  • 33
  • 51
0

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
  • 28,436
  • 30
  • 79
  • 95
0

.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
  • 32,487
  • 24
  • 164
  • 258
0

"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.
  • 18,002
  • 10
  • 71
  • 105
  • 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 Feb 06 '09 at 21:22
  • 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 Feb 06 '09 at 21:22
  • (I don't want to sound ungrateful just because I disagree, btw - thanks very much for the answer!) – Jon Skeet Feb 06 '09 at 21:27
  • 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 Feb 07 '09 at 00:28
  • @Jon Developers 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. Feb 07 '09 at 06:36
  • @Jon Are 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. Feb 07 '09 at 06:37
  • @Wedge Its 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. Feb 07 '09 at 06:38
  • Sorry with the last line - its a bit mixed up - should say String.appendReturnsSameStringBuilderNotANewCopy(). – mP. Feb 07 '09 at 07:43
  • @Wedge Go 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. Feb 08 '09 at 00:43
  • @Wedge It 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. Feb 08 '09 at 00:44
  • @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 Feb 08 '09 at 20:20
  • @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. Feb 08 '09 at 22:55
0

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

Alex Baranosky
  • 48,865
  • 44
  • 102
  • 150
  • 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. Feb 07 '09 at 07:45
  • 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 Feb 07 '09 at 08:15
0

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

Or "Attach" or "AttachTo".

Alex Baranosky
  • 48,865
  • 44
  • 102
  • 150
0

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
  • 7,580
  • 1
  • 30
  • 34
  • 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 Feb 08 '09 at 20:18
0

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

Benjol
  • 63,995
  • 54
  • 186
  • 268
0

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

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.

kofifus
  • 17,260
  • 17
  • 99
  • 173
0

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");
Gabriel
  • 1
  • 2
0

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
  • 9,860
  • 3
  • 34
  • 39
0

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
  • 9,860
  • 3
  • 34
  • 39
  • 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 Apr 16 '09 at 05:24
  • 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 Apr 16 '09 at 10:56
0

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");
Alex Norcliffe
  • 2,439
  • 2
  • 17
  • 21
0

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.

Justin Breitfeller
  • 13,737
  • 4
  • 39
  • 47