8

For the StringBuilder class, why not overload the += operator instead of a using a unique .Append() method?

Append() only concatenates strings so why did they not just overload += operator like so:

StringBuilder sb = new StringBuilder();
sb += "My string";

Is it a case of efficiency? Is it a case of convention or intuitiveness?

Thanks,

PeonProgrammer
  • 1,445
  • 2
  • 15
  • 27
  • 1
    Because... Then it's the same thing as a string? It's like asking why `List`s don't have += for adding an object... – Shahar Feb 21 '14 at 02:07
  • So why have a stringbuilder class? – PeonProgrammer Feb 21 '14 at 02:09
  • 3
    I wanted my comment to hint at how unsatisfied I was with Shahar's example. – PeonProgrammer Feb 21 '14 at 02:28
  • 2
    @PeonProgrammer - string += string is not concatenation. It's concatenation and assignement. Strings are immutable, so string += string creates a third string that is the two strings concatenated and then overwrites the original string variable with this new string. Stringbuilder, on the other hand, is mutable string manipulation, so .Append() does not create a new string to replace the old one.. doing so would nullify the benefits of Stringbuilder. So your question is basically, Why doesn't Stringbuilder act like a string? And the answer is because it's not a string, it's a Stringbuilder – Erik Funkenbusch Feb 21 '14 at 03:04
  • @Shahar - While I agree with you, there are several examples of the framework doing just that. For instance, Event handlers use += to essentially add an object to it's list, and -= to remove from the list. There have been some questionable choices made by the language designers in years gone by. – Erik Funkenbusch Feb 21 '14 at 03:10
  • 2
    You're getting from me a question up-vote, because your question is highly important to new programmers to understand the answer of Eric Lippert. Too many times encountered on new programmers doing such kind of mistakes. – Orel Eraki Feb 21 '14 at 19:54

1 Answers1

30

Arithmetical operations should be limited to types that act like arithmetical values. It is bad enough that the sum of two strings is a third string. Conflating the addition operation with string concatenation is a questionable choice because string concatenation obeys very few of the rules of addition; in particular, a + b != b + a.

But to go there for string builders -- which are by definition mutable state and not arithmetical values -- is horrid. The sum of two things should be a third thing that differs from the two summands. That is, a += b must have the same semantics as a = a + b and not a.MutateWith(b). If there isn't an assignment to a at the end then compound assignment is the wrong operator.

More generally: never make cutesy operator overloads. Operator overloads are there so that you can make two complex numbers add to a third, not so that you can make an customer plus a jar of peanut butter equal a purchase order, or some such silliness.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • So if I understand correctly- When someone wants to overload an operator, they should implement the overload in such a way that it behaves just like the arithmetical operation. It actually sounds so obvious now that I'm typing it but I never thought of how confusing a + b != b + a is when considering string concatenation. Thank you – PeonProgrammer Feb 21 '14 at 02:23
  • 7
    Care to explain why C# uses += and -= to add items to event handlers then? ;) – Erik Funkenbusch Feb 21 '14 at 03:11
  • 1
    @ErikTheViking To be fair, += on event handlers actually *does* produce a new delegate. Delegates are immutable, so `a += b` actually does assign a new, combined delegate to a. I admit it's not ideal, but it at least follows the biggest rule that Eric set out. – dlev Feb 21 '14 at 03:35
  • 3
    @ErikTheViking: What dlev said is correct. Just as it is unfortunate that `+` was chosen to mean concatenation on strings, it's equally unfortunate that `+` means sequential composition on delegates. But again, just like strings, two delegates add to a third. When you say `+=` on a delegate it does have the semantics of `a = a + b`. But I've never liked this feature of C#; it seems too cute to me. – Eric Lippert Feb 21 '14 at 14:19
  • @EricLippert & dlev - Well, learn something new every day, did not know delegates were immutable, and this was an assignment. So yes, in that context, makes more sense. – Erik Funkenbusch Feb 21 '14 at 15:33
  • Imo, Eric's answer is a fallout from an aggressive tie to a mathematical basis, an inability to overload that operator directly ([because of tie to "+" operator](http://stackoverflow.com/a/5202868/538763)), and more generally possibly as a deterrent to C++ abuses of the past (where there are separate overloads I believe). An SB += example: http://stackoverflow.com/a/2194671/538763. A similar question could be asked for += on a HashSet. – crokusek Mar 10 '14 at 23:05
  • @EricLippert Shouldn't they have put a restriction on arithmetic operator overload to only work with two objects of the same type and that the return type must be the same too to prevent such outrageous scenarios? – silkfire Nov 19 '20 at 13:54
  • @silkfire: Though that certainly seems reasonable, there are perf reasons to want to avoid that. Suppose for example we define a struct `Complex` and then define `op *` as taking `Complex, Complex` and returning `Complex`, and we also define an implicit conversion from `double` to `Complex`. Now we have `c * 1.5` in our program. What happens? We first convert 1.5 to `Complex`, and then call the multiplier that handles the general case. – Eric Lippert Nov 19 '20 at 19:31
  • 1
    @silkfire: But we could write a more efficient `Complex * double` user-defined operator that just multiplied the real and imaginary parts by the double; that's two multiplications. Without that we must first make `Complex` (1.5 + 0i) by calling the converter, and then do the usual four multiplication and two additions to multiply two complexes together. We can save more than half the work in this common case by having a special-purpose user-defined operator. – Eric Lippert Nov 19 '20 at 19:33
  • 2
    Also, it's not unreasonable to multiply a matrix by a scalar to get a new matrix. – Brian Nov 19 '20 at 21:13