csharplang icon indicating copy to clipboard operation
csharplang copied to clipboard

[Proposal]: User defined compound assignment operators (VS 18.0, .NET 10)

Open AlekseyTs opened this issue 10 months ago • 2 comments

User Defined Compound Assignment Operators

Summary

Allow user types to customize behavior of compound assignment operators in a way that the target of the assignment is modified in-place.

Design meetings

  • https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-04-02.md#user-defined-compound-assignment-operators

Motivation

C# provides support for the developer overloading operator implementations for user-defined type. Additionally, it provides support for "compound assignment operators" which allow the user to write code similarly to x += y rather than x = x + y. However, the language does not currently allow for the developer to overload these compound assignment operators and while the default behavior does the right thing, especially as it pertains to immutable value types, it is not always "optimal".

Given the following example

class C1
{
    static void Main()
    {
        var c1 = new C1();
        c1 += 1;
        System.Console.Write(c1);
    }
    
    public static C1 operator+(C1 x, int y) => new C1();
}

with the current language rules, compound assignment operator c1 += 1 invokes user defined + operator and then assigns its return value to the local variable c1. Note that operator implementation must allocate and return a new instance of C1, while, from the consumer's perspective, an in-place change to the original instance of C1 instead would work as good (it is not used after the assignment), with an additional benefit of avoiding an extra allocation.

When a program utilizes a compound assignment operation, the most common effect is that the original value is "lost" and is no longer available to the program. With types which have large data (such as BigInteger, Tensors, etc.) the cost of producing a net new destination, iterating, and copying the memory tends to be fairly expensive. An in-place mutation would allow skipping this expense in many cases, which can provide significant improvements to such scenarios.

Therefore, it may be beneficial for C# to allow user types to customize behavior of compound assignment operators and optimize scenarios that would otherwise need to allocate and copy.

Design meetings

  • https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-02-12.md#user-defined-instance-based-operators

AlekseyTs avatar Jan 27 '25 17:01 AlekseyTs

I was excited to see this feature proposal :)

Should readonly modifier be allowed in structures? It feels like there would be no benefit in allowing to mark a method with readonly when the whole purpose of the method is to modify the instance.

Re this: allowing readonly members can be quite sensible in the face of types with move-only semantics (just without built-in compiler errors/warnings; but these could be provided by an analyser even today, or we might get proper c# support for move-only types some day if we're lucky). As an example, this could be useful for something like a pooled-allocation, move-only, variable-size modular integer number type (you'd store the value (& maybe modulus - but you may want to share instances of these) in pooled arrays, which are mutated on operation like +=, but this can be written in a readonly method since its indirect), or for any other struct backed by a reference type which supports mutation directly. Even though this would not be the common use case of stuff like +=, it would be good to support it as there are legitimate use cases for marking them readonly imo.

Also, another question is how it works in readonly structs - it'd probably be good to still be able to define these on readonly structs, but their implementations (for the most part) probably need to be mutating. Some thought might need to be given to this - perhaps it's like init members where they're mutating anyway (at least by default, it would be good if you could still mark them readonly imo).

Thanks for reading :)

hamarb123 avatar Feb 02 '25 09:02 hamarb123

@hamarb123 please keep discussion in the discussion thread.

333fred avatar Feb 02 '25 16:02 333fred