Proposal: compound assignment operators should add KeyValuePair to dictionary if not present, just like regular assignment #2139
Replies: 12 comments
-
The C# language already supports compound assignment via an indexer. It sounds like you're asking for the C# compiler to behave different specifically when the indexer is being applied to |
Beta Was this translation helpful? Give feedback.
-
I'm asking for the compiler to supply a default lhs operand when performing compound assignment on a |
Beta Was this translation helpful? Give feedback.
-
The reason I don't think this is possible without breaking old code. Nor do I think it'd be a worthwhile change -- while I have had code like this before, and I do enjoy taking advantage of C++'s behavior, it's not done often enough to be worth the large effort required to enable something shorter. |
Beta Was this translation helpful? Give feedback.
-
How about using DictionarySlim.GetOrAddValueRef? |
Beta Was this translation helpful? Give feedback.
-
|
Beta Was this translation helpful? Give feedback.
-
Another option is: dictionary[key] = dictionary.TryGetValue(key, out var v) ? (v + val) : val
concurrentDictionary.AddOrUpdate(key, val, +) where However, I'm skeptical of this proposal as it is currently written. Is this really a common enough change that warrants either a new set of operators, or a breaking change? |
Beta Was this translation helpful? Give feedback.
-
I'm not the biggest fan of a new set of operators either. I've run into these situations often enough but I'm working on a 4X strategy game. Lots of collections. I don't know... It's hard for me to imagine anyone working on a similar project for long enough not running into this scenario at least a few times. (EDIT: I count 12 instances of this in my project) Perhaps a larger consideration is elegance and conforming with the expectations set by the behaviour of the regular assignment operator. I don't know about you, but when I first realised that I agree that the breaking change is unfortunate, and I get the feeling that this sort of thing isn't taken lightly. From a cost-benefit point of view, I'm not sure it's such a big issue. You'd fix some buggy code where the programmer has assumed that compound assignment mirrors regular assignment. Sometimes actually generating that exception might point towards a different issue that then become a bit more difficult to find. But that's a net benefit at best and a trade-off at worst. Then it's possible that a programmer takes an odd route, handles the key not found exception instead of checking for the existence of the key, and counts on that exception being generated to execute some other logic. But that sounds infinitesimally rare, and where that might occur the most common way to handle the exception would probably just be adding the element to the dictionary anyway, same thing as the proposal does. Pragmatically speaking, if it's worth anything, I'd guesstimate that the odds of this breaking change fixing something is way in excess of breaking anything, |
Beta Was this translation helpful? Give feedback.
-
Why? All of the compound assignment operators focus on combining an existing value with another expression - how does this make sense when there is no existing value? Knowing how regular assignment works, my intuition doesn't tell me to expect this to work: int foo = 42;
int bar += foo; |
Beta Was this translation helpful? Give feedback.
-
Furthermore to the above, with |
Beta Was this translation helpful? Give feedback.
-
Sure, that's fair, but how does it make sense to assign a value to an element that doesn't exist yet? It doesn't really, but in the case of dictionaries the implicit declaration in the event of assigning to a non-existent key makes a lot of sense when you consider the amount of boiler plate code that would be required otherwise. The intuitive process is: The language broke convention for the assignment operator so that this boiler plate code is no longer necessary. |
Beta Was this translation helpful? Give feedback.
-
No it didn't. The change is entirely at the library level. C# has no idea that Dictionary exists. |
Beta Was this translation helpful? Give feedback.
-
Sure, thanks for the correction. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Problem:
Regular assignment to a dictionary will create a new key (and assign the pertinent value) if one does not exist. So:
if (dict.ContainsKey(key)) { dict[key] = val; } else { dict.Add(key, val); }
Can be simplified to just:
dict[key] = val
And this is a great feature that helps keep a lot of otherwise ugly code much more readable. But the same shortcut doesn't work for compound assignment operators, which will generate an exception if the key is not already present in the dictionary. So, outside of operator overloading or extension methods (which at the moment I'm relying on to avoid ugliness) you're left with a variant of the above, such as:
if (dict.ContainsKey(key)) { dict[key] += val; } else { dict.Add(key, val); }
Proposal:
Have compound assignment operators add the key to the dictionary if the key isn't already present, the same way that regular assignment works. The sticky part is the value. I suggest using an implicit 0/false/default value for the left operand when deciding the initial value to pair to the key. In other words,
dict[key] -= 1
should performdict.Add(key, 0 - 1)
when the key is not present.Complications:
This is a breaking change, where say, a compound assignment operator wrapped inside a try block could trigger certain behaviour upon generating a key not found exception. Obviously, this will no longer be the case if the operator functionality is changed. As far as breaking changes go while this seems pretty unlikely, it's still a thing. A non-breaking version could use a new operator like =+=, but that’s probably too ugly to even consider.
Beta Was this translation helpful? Give feedback.
All reactions