views:

175

answers:

5

It certainly does not break from the standard practice of the .NET framework. When I see a a + b I always assume something new will be created.

static void Main(string[] args)
{
    var list = BuildList(ImmutableList<int>.Empty);
    var sum = (list + 500).Sum();
    Console.WriteLine(sum);
    Console.ReadLine();
}

static ImmutableList<int> BuildList(ImmutableList<int> list)
{
    if (list.Count < 1000)
    {
        return BuildList(list + list.Count);
    }
    return list;
}

Update

See Jon Skeet's post on what to name methods on immutable lists.

Surprising Responses

I am quite surprised to see so many answers that concur that this makes sense. In principle I also agree but it is way easier for me to read verbose code than it is for someone who is uncomfortable with terseness to read, well terse code. From my working experience they seem to be the majority.

+6  A: 

I personally would not recommend overloading operators like + for any class that isn't meant to be treated as a primitive. In particular, collections, in my opinion, should never overload operators.

Operator overloading makes sense when you have a small immutable class or struct that is meant to behave like a "primitive" type. However, when you start trying to do this for other classes, it really impacts maintainability.

I'd recommend making explicit method calls, instead.


After reading the comments, my recommendation would be to use Concat() (to match Enumerable.Concat in the Framework). Another option I would prefer would be Construct(), ala cons (though cons typically prepends), to make the usage very clear:

var list = BuildList(ImmutableList<int>.Empty);
var list2 = list.Concat(500); 
// Or: var list2 = list.Construct(500);
Reed Copsey
This is a `struct` that cannot be mutated in any way, so in essence it does behave exactly as an `int` would.
ChaosPandion
@ChaosPandion: No, it really doesn't. It's immutable like an int, but it's conceptually very different. A collection is conceptually not a primitive object.
Reed Copsey
@ChaosPandion: I'm not saying you ~can't~ do this - just that I feel it's adding something very unclear to your API, and likely to reduce the maintainability and understandability of your code dramatically.
Reed Copsey
@Reed - So lets say you could define any *punctuation* as an operator would you think something like `list :: 2` would be appropriate?
ChaosPandion
+1. Reed's opinion matches Microsoft's Framework Design Guidelines.
TrueWill
@ChaosPandion: I wouldn't do it. I'd much rather use method names. What the hell is "list :: 2" supposed to mean? If I was reading that code, I'd be scratching my head....
Reed Copsey
(BTW - this is just my opinion, and comes from having to debug C++ with lots of operator overloads too many times.... Life gets very hard, very quickly when people start overloading things in non-obvious ways)
Reed Copsey
@Reed - I guess Haskell and F# are really rubbing off on me...
ChaosPandion
@ChaosPandion: I'd personally use F# or Haskell when you want it - but don't pervert C# into looking more like F#. People have done that with C++, and it really goes awry :(
Reed Copsey
@Reed - What are your thoughts on a proper name for the "add" method?
ChaosPandion
@Reed - Oh and take it easy, this is experimental code.
ChaosPandion
@ChaosPandion: What's this method going to return? if you do `list = new IL([] {1,2,3}); list2 = list.Foo(500);`, what would list2 contain?
Reed Copsey
@Reed - `1,2,3,500`
ChaosPandion
@ChaosPandion: I'd probably use Concat, as it's behavior is really identical to Linq's concat (though for 1 item instead of a collection): http://msdn.microsoft.com/en-us/library/bb302894.aspx - If you don't like that, another good option would be Construct()
Reed Copsey
@Reed - Thanks, just remember some people ask questions simply out of curiosity. :)
ChaosPandion
@ChaosPandion: Of course! I'm just trying to help - sorry if it came across preachy ;) This is one where I feel fairly strongly (I inherited a huge project a few years back full of C++ code with lots of bugs from overloaded operators - made life very difficult for a good year :( )
Reed Copsey
+2  A: 

What does + mean in this context? It seems really unclear to me (without reading code). IList + IList I could see as maybe a union operator or combining the lists (keeping duplicates) or any number of other things. IList + int just confuses me. It seems to me a method with a clear name will make for much more readable code than an operator somebody will have to look up, or comments every time you use the overloaded operator.

Peter Leppert
What would you name this method?
ChaosPandion
Assuming this adds an element to the list, the link you provided to Jon Skeet's post is a good resource. I personally would probably throw my hat in as a vote for `.Cons()` or `.Add()` -- aside from mutability, this does the same as `.Add()` on a `List`.
Peter Leppert
@Peter - I am on the fence between `Cons` and `Concat`.
ChaosPandion
The cons operation puts a new element on the head of a list; the concat operation creates a new list containing all of the elements of the first list, then all of the elements of the second list. They are fundamentally different operations.
Gabe
@Gabe - See my dilemma? :)
ChaosPandion
+2  A: 

One thing about operators, is that people expect them to be relatively efficient. There's nothing to say that this should hold, but people do seem to expect it.

If internally, the structure of such a list allowed you to create a concatenated list by having it store references to the two it was sourced from (quite possible, especially considering that immutability negates the risk of confusing side-effects), then I'd go for it. If it was potentially to have to do a relatively expensive operation, then I wouldn't. "concatenate()" might make someone consider "do I really need to move this much memory around here in this tight loop I'm currently in, or should I consider a different approach" at a time when such a thought is appropriate.

Jon Hanna
I ran some performance tests and my implementation does surprisingly well with results similar to `string`. Obviously not as good but similar.
ChaosPandion
Though, "know that + is slow with strings" is often one of the first things told to newbies, precisely because they may assume otherwise (and then it gets overstated to the point of over avoiding it, but that's a different matter). At that speed, I think I'd lean against, but I wouldn't think it wrong of someone to do either.
Jon Hanna
@Jon - In the cases where you need a tight loop. I would say use a mutable list but keep it scoped to a single function.
ChaosPandion
Agreed, but remember that ultimately there is no code difference between + and Concat, the difference is only in the mind of the human being reading and writing the code. The effect is hence to encourage or discourage different approaches; it's a psychological thing about what the person does in a tight loop, rather than the practical thing of what they should do, and we want the psychology and the practical concerns to match.
Jon Hanna
+5  A: 

An immutable list of characters that overloads + makes sense; we call them strings. You could, by analogy, say that an immutable list of anything that overloads the + operator to invoke the Concat operation makes sense.

BTW, I recently created a similar function to what you're describing:

public static IEnumerable<T> Append<T>(this IEnumerable<T> list, T item)
{
    foreach (T i in list)
        yield return i;
    yield return item;
}

I decided that Append adds a single element to the list, while Concat adds a whole list to the end of the list.

Gabe
+1 - You know this is what I was thinking, but the confusion this seems to cause people really outweighs the conciseness of using it. Now I were to never use this outside of my personal projects then I would probably use it, but I want to use this at my job as well. *(I am so sick of the issues cause by nullable mutable lists.)*
ChaosPandion
Maybe I'm not confused because Python uses `+` for list concatenation, but I remember not being confused when I first saw it. What kind of people are confused by `list + list`?
Gabe
@Gabe, because some people don't *think*.
Joshua
@Gabe - That is perfect. I have my interface. :)
ChaosPandion
+1  A: 

I'd do it.

After all, a string is a list of characters.

And yes, if I saw <list> + <list> I'd immediately think concatenate (the only other possibility is vector sum and that's rare).

Joshua