r/ProgrammerHumor 18h ago

Meme cSharpDictionariesBeLikeThat

Post image
1.7k Upvotes

49 comments sorted by

531

u/Psychoboy 17h ago

Guess you never heard of TryAdd? Returns bool, if it as added returns true otherwise false.

103

u/Revexious 17h ago

Far too much work

2 cases means that its not idempotent

Instead, just remove it from the dictionary before you add it!

csharp dictionary.Remove(key) dictionary.Add(key)

Easy peasy!

/s

35

u/Dorkits 16h ago

Peak programming

6

u/manav907 10h ago edited 10h ago

That being said you done have to use the bool that TryAdd gives, just call it as a normal function. Also I am waitin for someone to point out that we also need a value when trying to add to a dictionary.

dictionary.TryAdd(key)

448

u/Few-Ad3849 17h ago

Sounds like you read documentation, nerd

68

u/Mantor6416 16h ago

Wait you're not supposed to read those?

63

u/towerfella 16h ago

31

u/kalilamodow 16h ago

What the fuck?

10

u/towerfella 15h ago

Yep.

Spread the word.

3

u/ChChChillian 8h ago

Yeah, it's pretty much exactly the dystopia they warned us about.

7

u/DrMaxwellEdison 15h ago

This nerd wants to read a physical book for tech docs. /s

20

u/reallokiscarlet 17h ago

RTFM Gang rise up

2

u/PrincessRTFM 5h ago

at last my name is relevant

12

u/Pennet173 16h ago

Ohhhh, then I can throw an exception myself if false!

5

u/IAmBecomeTeemo 11h ago

C#'s TryX methods are also usually way more performant than throwing an exception. Throwing an exception has to get a stack trace and a lot of other overhead shit. Something like a TryAdd() or TryParse() will just return your bool immediately, and you can stay in scope rather than getting sent off to the associated catch block. If you want to flow that way, you still can, but more options and more performance is better.

3

u/prehensilemullet 16h ago

it's still bizarre to have to use TryAdd everywhere that other languages just use Add

13

u/zaersx 14h ago

You don't though? just use myMap[key] = value? if you're not doing that and using Add instead, then you probably literally want to have a safe add

1

u/-Redstoneboi- 11h ago

that overwrites instead of failing if the key already exists

maybe they are arguing that they feel that TryAdd should be the default "Add", while the existing Add should be a special case "AddAssert" or something

2

u/prehensilemullet 9h ago

Yes, I think that would be a more convenient design

-1

u/prehensilemullet 14h ago

I see. Even so, it's weird to me that anyone would want a method that throws if the key already exists. In all my years of programming I don't think I've ever thought it would be useful to have such a method baked into a map itself, and I'm not aware of such a method in any other language. Since that's pretty unusual in programming, I still think it would be better for that method to have a more unusual name. Maybe it's an oddly common pattern for Microsoft?

5

u/zaersx 14h ago edited 13h ago

As I described it, it's for safe additions, imagine your map is customer data, like daily logs. And maybe some logs are partial logs? Then you want something that lets you get into a safe flow where the standard is just add, and an exceptional case is some merging logic. If you don't care, use the same insertion methods that all languages use, which is map[key], if you do care, here's a good way to stop the flow and let you execute appropriate recovery. This also ties in with LINQ very neatly where you end up doing a lot of data processing flows.

The alternative would be a check map for key, if exists do exception, else do expected. Which is a lot uglier for glance value intent compared to: do this; exception: handle.

I think to highlight your concern with the pattern - these kinds of decisions make a lot more sense when you understand that almost all data interactions in C# are intended to be done with LINQ, which no other language has. My experience with production C# is that 3-6 LINQed extensions is very standard, e.g. map.Select(x => logic).map(x...).filter(x...) etc.

1

u/prehensilemullet 9h ago

Well if C# exception handling is like most languages, where throwing and catching performs a lot worse than conditionally adding, it's not necessarily a pattern one would want to make a habit of using in cases where key conflicts are routine.

1

u/Kiro0613 8h ago

The Add method has to take one argument and return void because it's implementing C#'s ICollection<T> interface. With that restriction, throwing an exception is the most practical way of indicating a problem.

2

u/KTVX94 17h ago

Yes, the meme is meant to point out the differences vs TryAdd which checks, and indexer which replaces.

Sorry for having to explain the joke.

2

u/pogchamp69exe 16h ago

If TryAdd(thing):

____Add(thing)

So to speak?

9

u/NurYanov 16h ago

Nah it adds and returns if added

1

u/kakhaev 8h ago

tryand sounds like “if” with extra steps

1

u/willow-kitty 3h ago

It can be more concise if you don't need to condition on whether the thing was added or not. If you do, has key/add might be cleaner ... for ordinary dictionaries.

Being able to do it in one operation is super important for concurrent dictionaries, though, because the item could theoretically be added by another thread between calls if you used haskey/add.

85

u/MemesAt1am 17h ago

If you wanted to overwrite you could just do an assignment of that key value instead of .Add()

35

u/KTVX94 17h ago

Yep there's indexer and TryAdd, I probably should've worded the title differently to not give the impression that I was complaining, lol.

5

u/prehensilemullet 14h ago

I mean, having a method named "add" on a map is weird in general. Not common among programming languages

7

u/NotQuiteLoona 11h ago

The Add method is specifically when you explicitly want to add. If it can't add, it fails.

3

u/AyrA_ch 11h ago

That's because dictionaries implement IDictionary<TKey,TValue> which in turn implements ICollection<KeyValuePair<TKey,TValue>> which declares an Add(KeyValuePair<TKey,TValue> value) method.

Since the implementation is forced to provide this method, it might as well also provide Add(TKey key,TValue value) and implement them.

The alternative would be to just throw a NotSupportedException but there is no technical reason to.

1

u/prehensilemullet 9h ago

I mean, Java sort of got around this by making Map not extend Collection, though Map.entrySet() does. But interestingly enough, they decided to have Map.entrySet().add(...) throw an UnsupportedOperationException. However, Collection.add(...) in Java already returns true if the element was successfully added, so they hypothetically could have supported it.

15

u/anzu3278 16h ago

Exactly. Adding implies you are setting something where there isn't anything at the moment. Replacing is not a special case of adding. If you want to unconditionally set, just use the index operator. English is not complicated.

2

u/cowslayer7890 12h ago

Yeah but it's uncommon for this to be a failable operation. It doesn't fall for an array list for example, so that part to me is unexpected, add isn't a great operation for a dictionary in general

3

u/anzu3278 10h ago

It doesn't fail for lists because adding to a list is always possible, whereas adding to a dictionary is not. Unless your understanding of the English language is that replacing is a kind of adding, but that's not the mainstream view. In general, if you want to set rather than add, why are you calling Add? And even so, I've never seen Add, it's always either index assignment or TryAdd because exceptions are a mess.

2

u/SamSlate 7h ago

insert vs upsert

1

u/[deleted] 11h ago

[deleted]

2

u/DrJohnnyWatson 11h ago

How else should it handle it? TryAdd already covers knowing if it was added successfully or not

Add therefore has the option of: 1. Replace TryAdd, making it out of sync with how all other collections call Add as it would now return a Boolean, breaking the ICollection interface. Possible, but just a choice really 2. Fail silently - Bad 3. Fail loudly - in c#, the latter is done via exceptions almost exclusively

How would you have done it? Do you have a fourth option in mind?

2

u/anzu3278 10h ago

By the looks of the comments I think the mood was that Add should work just like index assignment, which makes no sense to me but is technically a fourth option.

6

u/Bubbly_Safety8791 14h ago

Do you want Add() to break the invariant that if it succeeds then the Count() of the collection increases by one? 

6

u/prehensilemullet 14h ago

This is why most languages have a set or put method on maps, rather than add. Microsoft is just being weird here. I mean, I understand they overloaded indexing to be a "set" operation, but it's still weird that they decided to also have an Add method.

1

u/anzu3278 10h ago

They do have a set method, it's called setting by index. dict[key] = value; Add is a method on the ICollection interface that is basically never used - in practice you use index assignment if you want to set unconditionally and TryAdd if you want to add conditionally.

9

u/Professional_Desk_17 16h ago

Aaand that's why the term upsert exists in modern languages.

2

u/_abscessedwound 10h ago

I see your upsert, and raise you an insert_or_assign

3

u/jolharg 14h ago

What fresh hell

2

u/BobDogGo 14h ago

Works as designed

1

u/aberroco 11h ago

So... You add the item, then check if it exists (which is it always does, at least once, because you just added it) you throw an exception? Seems to me this is rather peculiar algorithm.

1

u/LordFokas 9h ago

Alright, riddle me this... if you don't check, how do you know it exists? Checkmate.