Skip to content

Commit 07407e4

Browse files
BillWagnergewarren
andauthored
Apply suggestions from code review
Co-authored-by: Genevieve Warren <[email protected]>
1 parent 4a7689d commit 07407e4

File tree

1 file changed

+15
-17
lines changed

1 file changed

+15
-17
lines changed

docs/csharp/whats-new/tutorials/compound-assignment-operators.md

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -86,13 +86,11 @@ Final patrons arriving before curtain...
8686
Final arrivals processed - concert about to begin!
8787
```
8888

89-
This realistic scenario provides an excellent test case for measuring the performance benefits of compound assignment operators, as the frequent count updates mirror common patterns in real applications where objects are repeatedly modified.
90-
9189
Examine the starter `GateAttendance` record class:
9290

9391
:::code language="csharp" source="./snippets/CompoundAssignment/GateAttendance.cs" id="GateAttendanceStarter":::
9492

95-
The `InitialImplementation.GateAttendance` record demonstrates the traditional approach to operator overloading in C#. Notice how both the increment operator (`++`) and addition operator (`+`) create entirely new instances of `GateAttendance` using the `with` expression. Each time you write `gate++` or `gate += partySize`, the operators allocate a new record instance with the updated `Count` value, then return that new instance. While this approach maintains immutability and thread safety, it comes at the cost of frequent memory allocations. In scenarios with many operations—like our concert simulation with hundreds of attendance updates—these allocations accumulate quickly, potentially impacting performance and increasing garbage collection pressure.
93+
The `InitialImplementation.GateAttendance` record demonstrates the traditional approach to operator overloading in C#. Notice how both the increment operator (`++`) and addition operator (`+`) create entirely new instances of `GateAttendance` using the `with` expression. Each time you write `gate++` or `gate += partySize`, the operators allocate a new record instance with the updated `Count` value, then return that new instance. While this approach maintains immutability and thread safety, it comes at the cost of frequent memory allocations. In scenarios with many operations—like the concert simulation with hundreds of attendance updates—these allocations accumulate quickly, potentially impacting performance and increasing garbage collection pressure.
9694

9795
To see this allocation behavior in action, try running the [.NET Object Allocation tracking tool](/visualstudio/profiling/dotnet-alloc-tool) in Visual Studio. When you profile the current implementation during the concert simulation, you discover that it allocates 134 `GateAttendance` objects to complete the relatively small simulation. Each operator call creates a new instance, demonstrating how quickly allocations can accumulate in real-world scenarios. This measurement provides a concrete baseline for comparing the performance improvements you achieve with compound assignment operators.
9896

@@ -109,23 +107,23 @@ public void operator ++() => this.property++;
109107

110108
The key differences from traditional operators are:
111109

112-
- **Mutation**: They modify the current instance directly using `this`
113-
- **No new instances**: Unlike traditional operators that return new objects, compound operators modify existing ones
114-
- **Return type**: Compound assignment operators return `void`, not the type itself
110+
- **Mutation**: They modify the current instance directly using `this`.
111+
- **No new instances**: Unlike traditional operators that return new objects, compound operators modify existing ones.
112+
- **Return type**: Compound assignment operators return `void`, not the type itself.
115113

116114
When the compiler encounters compound assignment expressions like `a += b` or `++a`, it follows this resolution order:
117115

118-
1. **Check for compound assignment operator**: If the type defines a user-defined compound assignment operator (`+=`, `++`, etc.), use it directly
119-
2. **Fallback to traditional expansion**: If no compound operator exists, expand to the traditional form (`a = a + b`)
116+
1. **Check for compound assignment operator**: If the type defines a user-defined compound assignment operator (for example, `+=` or `++`), use it directly.
117+
2. **Fallback to traditional expansion**: If no compound operator exists, expand to the traditional form (`a = a + b`).
120118

121119
This means you can implement both approaches simultaneously. The compound operators take precedence when available, but the traditional operators serve as fallbacks for scenarios where compound assignment isn't suitable.
122120

123121
Compound assignment operators provide several advantages:
124122

125-
- **Reduced allocations**: Modify objects in-place instead of creating new instances
126-
- **Improved performance**: Eliminate temporary object creation and reduce garbage collection pressure
127-
- **Familiar syntax**: Use the same `+=`, `++` syntax developers already know
128-
- **Backward compatibility**: Traditional operators continue to work as fallbacks
123+
- **Reduced allocations**: Modify objects in-place instead of creating new instances.
124+
- **Improved performance**: Eliminate temporary object creation and reduce garbage collection pressure.
125+
- **Familiar syntax**: Use the same `+=`, `++` syntax developers already know.
126+
- **Backward compatibility**: Traditional operators continue to work as fallbacks.
129127

130128
The new compound assignment operators are shown in the following code:
131129

@@ -141,14 +139,14 @@ The remaining 10 allocations come from the initial creation of the `GateAttendan
141139

142140
This allocation reduction translates to real performance benefits:
143141

144-
- **Reduced memory pressure**: Less frequent garbage collection cycles
145-
- **Better cache locality**: Fewer object creations mean less memory fragmentation
146-
- **Improved throughput**: CPU cycles saved from allocation and collection overhead
147-
- **Scalability**: Benefits multiply in scenarios with higher operation volumes
142+
- **Reduced memory pressure**: Less frequent garbage collection cycles.
143+
- **Better cache locality**: Fewer object creations mean less memory fragmentation.
144+
- **Improved throughput**: CPU cycles saved from allocation and collection overhead.
145+
- **Scalability**: Benefits multiply in scenarios with higher operation volumes.
148146

149147
The performance improvement becomes even more significant in production applications where similar patterns occur at much larger scales—imagine tracking millions of transactions, updating thousands of counters, or processing high-frequency data streams.
150148

151-
Try identifying other opportunities for compound assignment operators in the codebase. Look for patterns where you see traditional assignment operations like `gates.MainFloorGates[1] = gates.MainFloorGates[1] + 4` and consider whether they could benefit from compound assignment syntax. While some of these operations are already using `+=` in the simulation code, the principle applies to any scenario where you're repeatedly modifying objects rather than creating new instances.
149+
Try identifying other opportunities for compound assignment operators in the codebase. Look for patterns where you see traditional assignment operations like `gates.MainFloorGates[1] = gates.MainFloorGates[1] + 4` and consider whether they could benefit from compound assignment syntax. While some of these operations are already using `+=` in the simulation code, the principle applies to any scenario where you repeatedly modify objects rather than creating new instances.
152150

153151
As a final experiment, change the `GateAttendance` type from a `record class` to a `record struct`. It's a different optimization, and it works in this simulation because the struct has a small memory footprint. Copying a `GateAttendance` struct isn't an expensive operation. Even so, you see small improvements.
154152

0 commit comments

Comments
 (0)