C# operator overload for `+=`?

99,592

Solution 1

Overloadable Operators, from MSDN:

Assignment operators cannot be overloaded, but +=, for example, is evaluated using +, which can be overloaded.

Even more, none of assignment operators can be overloaded. I think this is because there will be an effect for the Garbage collection and memory management, which is a potential security hole in CLR strong typed world.

Nevertheless, let's see what exactly an operator is. According to the famous Jeffrey Richter's book, each programming language has its own operators list, which are compiled in a special method calls, and CLR itself doesn't know anything about operators. So let's see what exactly stays behind the + and += operators.

See this simple code:

Decimal d = 10M;
d = d + 10M;
Console.WriteLine(d);

Let view the IL-code for this instructions:

  IL_0000:  nop
  IL_0001:  ldc.i4.s   10
  IL_0003:  newobj     instance void [mscorlib]System.Decimal::.ctor(int32)
  IL_0008:  stloc.0
  IL_0009:  ldloc.0
  IL_000a:  ldc.i4.s   10
  IL_000c:  newobj     instance void [mscorlib]System.Decimal::.ctor(int32)
  IL_0011:  call       valuetype [mscorlib]System.Decimal [mscorlib]System.Decimal::op_Addition(valuetype [mscorlib]System.Decimal,
                                                                                                valuetype [mscorlib]System.Decimal)
  IL_0016:  stloc.0

Now lets see this code:

Decimal d1 = 10M;
d1 += 10M;
Console.WriteLine(d1);

And IL-code for this:

  IL_0000:  nop
  IL_0001:  ldc.i4.s   10
  IL_0003:  newobj     instance void [mscorlib]System.Decimal::.ctor(int32)
  IL_0008:  stloc.0
  IL_0009:  ldloc.0
  IL_000a:  ldc.i4.s   10
  IL_000c:  newobj     instance void [mscorlib]System.Decimal::.ctor(int32)
  IL_0011:  call       valuetype [mscorlib]System.Decimal [mscorlib]System.Decimal::op_Addition(valuetype [mscorlib]System.Decimal,
                                                                                                valuetype [mscorlib]System.Decimal)
  IL_0016:  stloc.0

They are equal! So the += operator is just syntactic sugar for your program in C#, and you can simply overload + operator.

For example:

class Foo
{
    private int c1;

    public Foo(int c11)
    {
        c1 = c11;
    }

    public static Foo operator +(Foo c1, Foo x)
    {
        return new Foo(c1.c1 + x.c1);
    }
}

static void Main(string[] args)
{
    Foo d1 =  new Foo (10);
    Foo d2 = new Foo(11);
    d2 += d1;
}

This code will be compiled and successfully run as:

  IL_0000:  nop
  IL_0001:  ldc.i4.s   10
  IL_0003:  newobj     instance void ConsoleApplication2.Program/Foo::.ctor(int32)
  IL_0008:  stloc.0
  IL_0009:  ldc.i4.s   11
  IL_000b:  newobj     instance void ConsoleApplication2.Program/Foo::.ctor(int32)
  IL_0010:  stloc.1
  IL_0011:  ldloc.1
  IL_0012:  ldloc.0
  IL_0013:  call       class ConsoleApplication2.Program/Foo ConsoleApplication2.Program/Foo::op_Addition(class ConsoleApplication2.Program/Foo,
                                                                                                          class ConsoleApplication2.Program/Foo)
  IL_0018:  stloc.1

Update:

According to your Update - as the @EricLippert says, you really should have the vectors as an immutable object. Result of adding of the two vectors is a new vector, not the first one with different sizes.

If, for some reason you need to change first vector, you can use this overload (but as for me, this is very strange behaviour):

public static Vector operator +(Vector left, Vector right)
{
    left.x += right.x;
    left.y += right.y;
    return left;
}

Solution 2

You can't overload += because it isn't really a unique operator, it's just syntactic sugar. x += y is just a shorthand way of writing x = x + y. Because += is defined in terms of the + and = operators, allowing you to override it separately could create problems, in cases where x += y and x = x + y didn't behave in the exact same way.

At a lower level, it's very likely that the C# compiler compiles both expressions down to the same bytecode, meaning that it's very likely the the runtime can't treat them differently during program execution.

I can understand that you might want to treat it like a separate operation: in an statement like x += 10 you know that you can mutate the x object in place and perhaps save some time/memory, rather than creating a new object x + 10 before assigning it over the old reference.

But consider this code:

a = ...
b = a;
a += 10;

Should a == b at the end? For most types, no, a is 10 more than b. But if you could overload the += operator to mutate in place, then yes. Now consider that a and b could get passed around to distant parts of the program. Your possible optimization could create confusing bugs if your object starts to change where code doesn't expect it to.

In other words, if performance is that important, it's not too hard to replace x += 10 with a method call like x.increaseBy(10), and it's a lot clearer for everyone involved.

Solution 3

This is because of the same reason that the assignment operator cannot be overloaded. You cannot write code that would perform the assignment correctly.

class Foo
{
   // Won't compile.
   public static Foo operator= (Foo c1, int x)
   {
       // duh... what do I do here?  I can't change the reference of c1.
   }
}

Assignment operators cannot be overloaded, but +=, for example, is evaluated using +, which can be overloaded.

From MSDN.

Solution 4

I think you'll find this link informative: Overloadable Operators

Assignment operators cannot be overloaded, but +=, for example, is evaluated using +, which can be overloaded.

Solution 5

This is because of this operator can't be overloaded:

Assignment operators cannot be overloaded, but +=, for example, is evaluated using +, which can be overloaded.

MSDN

Just overload + operator, because of

x += y equal to x = x + y

Share:
99,592
Mathias Lykkegaard Lorenzen
Author by

Mathias Lykkegaard Lorenzen

Updated on July 17, 2022

Comments

  • Mathias Lykkegaard Lorenzen
    Mathias Lykkegaard Lorenzen almost 2 years

    I am trying to do operator overloads for +=, but I can't. I can only make an operator overload for +.

    How come?

    Edit

    The reason this is not working is that I have a Vector class (with an X and Y field). Consider the following example.

    vector1 += vector2;
    

    If my operator overload is set to:

    public static Vector operator +(Vector left, Vector right)
    {
        return new Vector(right.x + left.x, right.y + left.y);
    }
    

    Then the result won't be added to vector1, but instead, vector1 will become a brand new Vector by reference as well.

  • Sebastian Mach
    Sebastian Mach almost 13 years
    Personally, I would change it's just syntactic sugar to it's just syntactic sugar in C#; otherwise, it sounds too general, but in some programming languages, it is not just syntactic sugar but might actually give performance benefits.
  • benzado
    benzado almost 13 years
    If you really care about performance, you're not going to mess around with operator overloading, which only makes it harder to tell what code is being invoked. As for whether messing up the semantics of += is your own problem... that's only true if nobody else ever has to read, maintain, or execute your code.
  • benzado
    benzado almost 13 years
    For simple (int, float, etc.) types, += could probably be optimized by a smart compiler, because arithmetic is simple. But once you're dealing with objects, all bets are off. Any language faces pretty much the same problems. This is why operator overloading is evil.
  • Jouke van der Maas
    Jouke van der Maas almost 13 years
    Stating that it's the case is not answering why.
  • VMAtm
    VMAtm almost 13 years
    @Jouke van der Maas And how do you want me to answer why it is not possible? It is impossible by design, what else can I say?
  • Jouke van der Maas
    Jouke van der Maas almost 13 years
    Why they designed it this way; that's what the question is, really. See some of the other answers.
  • VMAtm
    VMAtm almost 13 years
    @Jouke van der Maas Well, I'm not the C# team member to explain why this design is true. But I've updated the answer with some additional info. Hope since that my answer will satisfy you.
  • msedi
    msedi almost 13 years
    Hello, benzado. In some way you are right, but what we have is a platform for high-performance computing to create prototype applications. In one way we need to have the performance, on the other side we need a simple semantic. In fact we also like to have more operators than C# currently delivers. Here I'm hoping for C# 5 and the compiler as a service technique to get more out of the C# language. Nevertheless as I grew up with C++ and would appreciate if there are a little more features from C++ in C#, altough I would not like to touch C++ again since I#m doing C#.
  • benzado
    benzado almost 13 years
    Engineering is all about tradeoffs; everything you want comes with a price.
  • Shimmy Weitzhandler
    Shimmy Weitzhandler about 12 years
    @pickypg - this comment is not related to this thread: please undelete your answer, it does answer my question, I think I have no choice but to use your method, I thought there is some better way to solve it.
  • ThunderGr
    ThunderGr about 10 years
    "Strange behavior" only if you have been "born" programming in C# :p. But, since the answer is correct and very well explained, you get my +1, as well ;)
  • Assimilater
    Assimilater almost 8 years
    @ThunderGr No, it's pretty strange no matter which language you're looking at. To make the statement v3 = v1 + v2; result in v1 being changed as well as v3 is unusual
  • Şafak Gür
    Şafak Gür over 7 years
    Arithmetic operators return new instances by convention - hence they are usually overridden on immutable types. You can't add a new element to a List<T> using an operator like list += "new item", for example. You call its Add method instead.
  • Bojidar Stanchev
    Bojidar Stanchev almost 4 years
    @JoukevanderMaas Answering the "Why" question is not always possible.
  • VMAtm
    VMAtm almost 4 years
    @BojidarStanchev This comment is way too old to respond to it right now. I edited the answer a number of times since that.
  • Bojidar Stanchev
    Bojidar Stanchev almost 4 years
    @SebastianMach The question is specifically tagged with c# and dotnet tags. Obviously, in c++ for example, '+' and '+=' (and even '=') can be overloaded separately.
  • Sebastian Mach
    Sebastian Mach almost 4 years
    @BojidarStanchev: True that. I apologize for my 9 years younger self :-D
  • ToolmakerSteve
    ToolmakerSteve over 2 years
    I realize this is a very old answer. But as per the multiple upvotes about the "very strange behavior" of the last snippet: That snippet should be REMOVED. Its behavior is a very bad idea. Its no longer just a + operator, so it should not be given the symbol +.
  • VMAtm
    VMAtm over 2 years
    @ToolmakerSteve It's plus operator with mutable structure (which is questionable solution, yes). However, this answer here is more than 10 years, so I don't think that such edit will change something