Which dictionary to choose in C# and which one is dangerous

2021 ж. 13 Қаз.
100 240 Рет қаралды

Subscribe: bit.ly/ChapsasSub
Check out my courses: dometrain.com
Become a Patreon and get source code access: / nickchapsas
Hello everybody I'm Nick and in this video I will talk about the different dictionary types in C# and also the hashtable and how we can use them in different scenarios. I will also talk about one of the most common pitfalls that I've personally have fallen into unknowingly.
Don't forget to comment, like and subscribe :)
Social Media:
Follow me on GitHub: bit.ly/ChapsasGitHub
Follow me on Twitter: bit.ly/ChapsasTwitter
Connect on LinkedIn: bit.ly/ChapsasLinkedIn
Keep coding merch: keepcoding.shop
#csharp #dotnet

Пікірлер
  • For the record, whether the ImmutableDictionary is smart about allocations during its Add/Update/Remove operations doesn't really matter to me since I haven't met a single person that was aware of its underlying data structure. I personally used to choose an ImmutableDictionary because all I want is to return a dictionary that you can't change its values in any way, so I can't get behind a data structure that is smart about how it can be changed into a new datastructure efficiently when that's not the usecase I wanted anyway. Getting a value is O(log n) and that's all that matters to me. Of course this is just me and it's just one usecase but it looks like I much rather go with a ReadOnlyDictionary for that specific usercase. This also has to do with C# not being an immutability first language. When ImmutableDictionary is an AVL tree and ReadOnlyDictionary is a hash table, but then the "readonly" keyword is used to create immutable elements in your code, then you know that naming is kinda inconcistent and it leaves a lot room for assumptions.

    @nickchapsas@nickchapsas2 жыл бұрын
    • Thank you for creating great content, as always. How does the ReadOnlyDictionary perform?

      @LinusSwanberg@LinusSwanberg2 жыл бұрын
    • The idea of immutable dictionary is to allow creating versions without a full copy. If you just want to return a readonly dictionary then you should just do that. But aside from that great episode!

      @talwald1680@talwald16802 жыл бұрын
    • @@LinusSwanberg The Readonlydictionary performance depends on the performance of the IDictionary implementation passed to its constructor. Normally this is just Dictionary, so it's O(1), but someone could make a worse implementation if they wanted to and it would make the corresponding Readonlydictionary worse.

      @notmeprobably_@notmeprobably_2 жыл бұрын
    • I have similar issues where I want to return a read-only instance of a collection from a method, but I would like that instance to be mutable inside the method that is generating it. I ended up using one of the read-only interfaces that most collections implement (Dictionary implements IReadOnlyDictionary so I can return an instance directly without using any sort of wrapper, same with List and Arrays which implement IReadOnlyList which in turn extends IReadOnlyCollection). The only wrapper I use is the ReadOnlyObservableCollection, but that is only in WPF applications.

      @Andrei15193@Andrei151932 жыл бұрын
    • So I ran my own BenchmarkDotNet results and just to be sure, a few home cooked ones. I'm baffled that ImmutableDictionary reads are so slow. Why would they chose to design/engineer it this way? If it means anything, the results are slightly better than a SortedDictionary.

      @urbanelemental3308@urbanelemental33082 жыл бұрын
  • Topic for the next video: "When you should use structs in C#"

    @pawetarsaa9904@pawetarsaa99042 жыл бұрын
    • In my 4+ years of experience never used

      @clashclan4739@clashclan47392 жыл бұрын
    • Also would be good to cover, when an abstract type makes sense instead of an interface.

      @StephenOwen@StephenOwen2 жыл бұрын
    • @@clashclan4739 Best usage of structs are for small simple types that you know arent going to be arbitrarily grow over time. Vectors, Color Values, Matrices, Quaternion (rotations). And you can make copies of them easily without allocating more memory.

      @Andrew90046zero@Andrew90046zero2 жыл бұрын
    • The clickbait titles always make my eyes roll but then the content is mostly informative at least.

      @peteruelimaa4973@peteruelimaa4973 Жыл бұрын
    • @@clashclan4739 As a quick guideline use structs when the size does not exceeds 16 bytes, take into account that a reference is 8 bytes in most systems so 2 strings are already 16 bytes in pointers. Structs can be good because if used correctly with no boxing/unboxing the GC does not need to clean them up because they are stack allocated.

      @alejandroguardiola9085@alejandroguardiola90853 күн бұрын
  • Well, what about HashSet?

    @wobuntu@wobuntu2 жыл бұрын
  • 2 words of caution about ConcurrentDictionary: one is more obvious - Linq with ConcurrentDictionary is not thread safe, use built-in methods like .ToArray() first/instead; TryAdd overload with func which creates instance - the factory funk is not thread protected and can be entered more than once for the same key!

    @ArtemPyatkovsky@ArtemPyatkovsky2 жыл бұрын
  • "in which case... ...sorry." Fantastic delivery hahaha

    @vertxxyz@vertxxyz2 жыл бұрын
  • AVL Tree time complexity is o(lgn) for searching, insert and delete. Hash table have constant average time complex but with o(n) worst case caused by the hash collision.

    @peterdeshazer2986@peterdeshazer29862 жыл бұрын
  • SortedDictionary should be here too. The word "dictionary" and the hash table data structure were synonyms to me for a long time too until I learned that "dictionary" is just an abstract type that supports storing and getting value by key with many possible implementations e.g. hash tables and BSTs (I learned it from Skiena's book). It's also interesting how the naming is done in other languages. In c++ standard library, for example, dictionaries are named "maps", and the type name doesn't specify the underlying data structure, but rather the fact if it's ordered or not, just like in .NET: Dictionary std::unordered_map (hash table). SortedDictionary std::map (red-black tree). While in java they decided to make it more explicit: TreeMap and HashMap (both implement Map interface though). Also, in .NET there's also OrderedDictionary (not to be confused with SortedDictionary :=) ).

    @realkompot3904@realkompot39042 жыл бұрын
    • Thank you for the book recommendation.

      @SlackwareNVM@SlackwareNVM Жыл бұрын
    • A map is what we also call an associative Array, it's a data structure that's more of a toolbox than a specific structure See Lua Tables for an easy overview

      @LiveErrors@LiveErrors7 ай бұрын
  • Teacher: kids, what is result 2 + 2? Nick: 69 to the power of 420

    @user-fp6cr1wi2q@user-fp6cr1wi2q2 жыл бұрын
    • I send these videos to my co-workers because they are informative, but sometimes I forget how terrible/terrific his number choices are

      @leathakkor@leathakkor2 жыл бұрын
  • The last part with performance result is very interesting. Thank's Nick! This adds a clearer picture to the subject and proves some statements are right/wrong.

    @MrAndrei4777@MrAndrei47772 жыл бұрын
  • Hi Nick Thanks for this great video. I like that they are to the point, not tiring and teaching us something. Keep up with great work you doing.

    @gami195@gami1952 жыл бұрын
  • nick, you're fantastic, thank you so much for these types of videos. they really do help.

    @WillEhrendreich@WillEhrendreich2 жыл бұрын
  • Your title scared me. I was sure you were going to say Dictionary was the dangerous one, and I was like "well I'll watch the video and see what I need to refactor"!

    @brianm1864@brianm18642 жыл бұрын
    • I was worried he was gonna say concurrent dictionary - luckily not, it's too useful in certain situations

      @orterves@orterves2 жыл бұрын
  • I am amateur developer - with no professional skills - but I was thinking that knowing some patterns, syntax and object thinking is enough... but your channel shows to me, that there is much more!!! Thanks a lot for you work - you help (not only me - I am pretty sure) a lot with understanding the background and answering important questions to the question: "But why?" :)

    2 жыл бұрын
  • ImmutableDictionary actually had better performance than I expected. Great video and thanks for the insight in it's internal datastructure!

    @twiksify@twiksify2 жыл бұрын
  • Great to see they fixed the api from hashtable & synchronized.hashtable to dictionary & concurrentDictionary. In the former the underlying hashtable could still be altered apart from the synchronized.hashtable.

    @ryan-heath@ryan-heath2 жыл бұрын
  • Thank you Nick, as always very nice explained!

    @oleksandr.tomashchuk@oleksandr.tomashchuk2 жыл бұрын
  • A common use case for concurrency is a desire to have a lock-free data structure that supports single-writer, multiple readers in a thread-safe way and that is does not require any locks. Long ago I created such a data structure by tweaking the built-in Dictionary class. In fact the tweak was quite minimal - the main problem with the built-in dictionary class that causes a problem for concurrent reading and writing is that the resize operation (needed sometimes when adding an item to the dictionary) does not take concurrency into account and ends up updating the backing array reference before copying the elements from the old array to the new array. This creates a race-condition whereby readers will temporarily see a version of the dictionary where elements are missing. Tweaking this one piece of the dictionary array expansion makes it thread-safe for single-writer/multiple-readers. I combined this with a read-only interface that is given to readers to prevent them from attempting to modify then completes the picture. Oh, and for some reason I also had to remove the ability to remove items from the dictionary...

    @crikey4336@crikey43366 ай бұрын
  • Very insightful. Thank you Sir.

    @queenstownswords@queenstownswords2 жыл бұрын
  • If you haven’t already, would you please create a video about thread safety? It is something one doesn’t need to care about most of the times but a very critical topic.

    @hemant-sathe@hemant-sathe2 жыл бұрын
  • Great video! I learned a lot again!

    2 жыл бұрын
  • Some years ago I had issues finding the bottleneck in my code, the problem was that I used an object with two values as the key in a dictionary, I also found that a custom comparer class would hurt the performance of the dictionary. Just a warning to everyone.

    @casperhansen826@casperhansen8262 жыл бұрын
  • Good video. Thanks!

    @expansivegymnast1020@expansivegymnast1020 Жыл бұрын
  • SortedDictionary (missing in this video) has a nice bonus feature - it never fragments the LOH, what hashtable/Dictionary very well do on large amount of data.

    @cabriolex@cabriolex11 ай бұрын
  • Aren't SortedList, SortedDictionary and PriorityQueue considered dictionaries as well?

    @neociber24@neociber242 жыл бұрын
    • Yes, as there are addressed by key and return a value.

      @Sebazzz1991@Sebazzz19912 жыл бұрын
    • Came here to ask about those...

      @Erlisch1337@Erlisch13372 жыл бұрын
  • Thanks Nick, that was really interesting and good to know about the drawbacks of the ImmutableDictionary! When writing my own internal code I will often use IReadOnlyDictionary (interface) as the return/argument type but pass through my normal (mutable) dictionary anyway. I know there's nothing stopping my code from examining the type / casting this and mutating it anyway, but since it's my code and I'm respecting the input type then it feels safe to me (Looking back on it I don't think I ever cast anything anyway)! What are your thoughts on this?

    @Saltxwater@Saltxwater2 жыл бұрын
  • 69 for a random number great choice nick!!!

    @lalithmahadev5027@lalithmahadev50272 жыл бұрын
    • Looking at the previous video, there's certainly something Nick is trying to tell us

      @pog8599@pog85992 жыл бұрын
    • Spotted 420 as well O.o

      @bl1tz229@bl1tz2292 жыл бұрын
  • that is very interesting, I guess because the ImmutableDictionary have to make copies of itself using an AVLTree is better with the memory because in a hash Table you have to allocate space even for the items that has not been added to the Dictionary I mean is not that much considering it is a pointer space so basically 64 bits in 64 systems for every item between the last computed hash and the new computed hash, so Immutable may be more memory efficient(I mean one instance will take less space than the equivalent instance of a dictionary)

    @alejandroguardiola9085@alejandroguardiola9085 Жыл бұрын
  • Thanks for clearing up any doubts about your age at 2:20

    @jan5310@jan53105 ай бұрын
  • Hi, I love your videos. Why only some videos allow translation automatically?

    @fernandovictor3092@fernandovictor30922 жыл бұрын
  • Thanks bro

    @sergeymigel4680@sergeymigel4680Ай бұрын
  • Since get is the only valid usecase on immutable dictionary I think the extra time it takes is fine. I’m thinking a valid performance comparison on immutable dictionary would be time it takes to create an immutable dictionary from an existing (sizable) dictionary, compared to creating a new read only dictionary. I can only imagine these things are hydrated in one method as a dictionary and returned or passed in as an immutable

    @DummyFace123@DummyFace123 Жыл бұрын
  • Are immutable dictionaries backed by an AVL tree to store the data densely? Presumably the hashtable dictionaries have a sparse array to enable adding without collisions whereas the AVL tree shouldnt get added to? Thanks for the video!

    @Deemo_codes@Deemo_codes2 жыл бұрын
    • I don't know if it's just about storage but also about being efficient with the Add/Update/Remove operations and memory. That being said there is a proposal to move from AVL trees to B+-trees here: github.com/dotnet/runtime/issues/14477

      @nickchapsas@nickchapsas2 жыл бұрын
  • Thanks for great videos... do you have any comments or measurements for SortedConcurrentDictionary?

    @erikthysell@erikthysell2 жыл бұрын
  • I think that one thing wasn't specified. The 'GetElement' benchmark should be split into one-by-one (where keys are stored next to each other in the memory) and completely randomly. I believe that AVL Tree would significantly change the score due to the memory locality on CPU caches. Exactly the same reason why Unity is developing DOTS.

    @mastermati773@mastermati7732 жыл бұрын
    • It shouldn't matter that's why I didn't do that. Because the implementation behind the scenes should be irrelevant to your choice. You care about an "Immutable Dictionary" which implies that is an immutable verison of the Dictionary which is known to be a hashtable. The only difference between the two is implied to be the immutability factor.

      @nickchapsas@nickchapsas2 жыл бұрын
  • Hello, Nick! Thank you so much for such interesting videos! I want to ask you about using ContinueWith for async tasks: when I want to fill a dictionary with keys and values (counters) from different sources I use Task.WhenAll with async queries that continue with adding results to a dictionary. Is it a suitable case for ContinueWith using or can you suggest a better solution for my case? Thank you in advance! Have a nice day!

    @user-hu4dp5io7b@user-hu4dp5io7b2 жыл бұрын
  • For add operations benchmark was initial capacity set to itemCount? Was strings used? I really wonder if dictionary be free memory alloc.

    @fedormorozov8255@fedormorozov82552 жыл бұрын
  • Nick, after some quick research (and reading the comments), I think this video isn't correct. 1. I suspect that the benchmark results shown are consistent with O(1): Add runs in 0.95us then 1.143us then 1.0136us. The numbers are not good, but at the same time, if they are only a constant factor of 3 slower than the HashMap implementation, then this is not an important difference. 2. If the ImmutableDictionary uses structural sharing, then it does NOT allocate the entire dictionary for each add. The clue is in the name: both the old and new dicts share the majority of their internal structure, only allocating the differences. 3. Common dictionary implementations that utilize structural sharing are, depending on who you ask, "O(1) amortized", "O(log32 n)" or "O(log n) for n's larger than the number of atoms in the visible universe". All of these terms refer to the fact that it is theoretically O(log n), but indistinguishable from O(1) using any benchmark performed on hardware that can exist in our universe. 4. Structural sharing does require a generational garbage collector in order be efficient with memory allocations. If properly implemented and used, almost all "allocations" do not survive generation 0. And generation 0 should be implemented as a fixed allocation anyway, so that "real" allocations are not needed. I don't know the internals of dotnet garbage collection, but my quick look at the documentation does suggest some kind of generational garbage collector. But I'm not sure how much it is optimized for structural sharing datatypes.

    @upgradeplans777@upgradeplans7772 жыл бұрын
    • Get on ImmutableDictionary is definately not O(1) in terms of speed and Add isn't either. The reason why Add makes it harder to notice is because the benchmark result is within margin of error but consistent with how you would see an O(log n) operation look over time especally in those sizes of collection. Add will not allocate the whole collection but since you will be allocating to the new object, because the function is pure, you just lost the old reference to the old immutable array which needs to be GCed now. I have not tested this last bit so I could be wrong though but in any case, Add isn't really a concern to me because I would never mutate and immutable dictionary. Get is the only operation I would ever run on it and I would do that assuming it is O(1) which it is not.

      @nickchapsas@nickchapsas2 жыл бұрын
    • @@nickchapsas Perhaps the naming convention is a bit confusing, but structural sharing was definitely invented for the purpose that you say you are not willing to use it for. (The purpose of managing changing data with immutable datatypes.) "Immutable" refers to the fact that the object does not mutate, and structural sharing is merely one technique that exists within that category. Another common name for structural sharing datatypes is "Persistent" datatypes. However, the category of persistent datatypes is also much larger and not even always immutable. I'm not a regular .NET user, so I cannot say whether this ImmutableDictionary is implemented sensibly, but I looked up its documentation, and it is meant to be a structural sharing datatype. I also cannot say whether the .NET garbage collection is any good. But again, the documentation tells me it is a generational GC. (Generational GC is the correct GC type to use with structural sharing.) As for whether it is O(1) or not: Normally these datatypes have a branching factor of 32. This means that Adds and Gets use 1 indirection for dictionaries with 1..32 entries, 2 indirections for dicts with 32..1024 entries, 3 indirections for dicts with 1024..1048576 entries, and 4 indirections for dicts with 1048576..33554432 entries. With 8 indirections, you can have 1 terra-entry. There is no computer in existence today that can reasonably store that in RAM. So yes, the algorithm very much is a O(log n) algorithm. But if your code is written to be run on actual hardware, this maximum of 8 indirections is an insignificant factor.

      @upgradeplans777@upgradeplans7772 жыл бұрын
    • @@upgradeplans777 Here is the thing that you're mainly missing. I shouldn't know or care about any of this. It should all be abstracted from me. All I care about is having an immutable hashtable. Hashtable is obsolete so the instruction for a modern hashtable (with an average O(1) time complexity in operations) is to use Dicitonary. Then I use ConcurrentDictionary for its thread safety and the assumption of pretty much everyone who looks at the name is that when I want an immutable dictionary I go for ImmutableDictionary. The problem here is that I no longer have a Hashtable anymore. This is all there is to it.

      @nickchapsas@nickchapsas2 жыл бұрын
    • @@nickchapsas The usage of the word immutable in the name "ImmutableDictionary" is the conventional way it is used. Perhaps this is an unfortunate artifact, I don't have an opinion about that. But when I read ImmutableDictionary in this video, I did expect a structural sharing datatype with "O(1) amortized" performance, and it is my opinion that it should not use that name if it is not implementing a structural sharing datatype with O(1) amortized performance. (So, in that sense, I am saying the opposite of what you are saying when you say that the name is misleading.) A proper implementation of a structural sharing hashmap/hashtable will have "O(1) amortized" performance. Which is also the most that normal hashmaps give by the way, because they do not maintain theoretical O(1) performance when there are collisions. I will also note that a structural sharing hashmap/hashtable still is a hashmap/hashtable. It just also includes the structural sharing implementation. Which is apparently the part that is leading to this confusion. If the ImmutableDictionary is slow, then that is a performance issue with its implementation. But as I explained, the largest structure that fits in RAM will at most be 8 times as slow as an empty one. You yourself often enough point out that it isn't enough to strictly look at the theoretical performance, but to also take the real-world implications into account. I do think that, if you were to look at this type of datastructure in more detail, that you will agree that it has a sensible and modern design that can be tuned for high performance with large amounts of in-memory data. (If you don't trust this C# implementation, perhaps another immutable hashmap.) Still, it is true that most languages are not tuned for structural sharing, and therefore it can be a constant factor slower than using a mutable hashmap. I will caveat that again by saying that all of this depends on the datastructure being properly implemented with a branch factor of 32, ofcourse.

      @upgradeplans777@upgradeplans7772 жыл бұрын
  • Nick, do you try to implement api versioning into a minimal api?

    @claudiopedalino337@claudiopedalino3372 жыл бұрын
  • I remember when .net 1 came out. That was ages ago. But I've only worked professionally with .net 2 and above. Anyways I never heard of this immutable dictionary. Now I know that it has a very specific use case...when you need an avl tree.

    @pqsk@pqsk Жыл бұрын
  • Goes and updates a few local caches using Dictionary to ConcurrentDictionary....

    @petermanger9047@petermanger90472 жыл бұрын
  • What about SortedList? Which I always thought was a terrible and confusing name for a Dictionary class. And there's also SortedDictionary, but I'm not sure what the difference is.

    @PrometheusMMIV@PrometheusMMIV5 ай бұрын
  • I didn't see the same degradation with ImmutableDict at all. New snapshots of the dict seem to be just a few copied nodes but mostly all the same nodes in the new dict as well. It's a tree for a good reason, otherwise it would be much easier to just clone a normal dict wouldn't it? Even if making a bunch of new snapshots (on an already very large dict) and keeping them in memory there was only a slight increase in the total number of nodes when I tried mem-profiling in VS. Strange...

    @MixedApp@MixedApp2 жыл бұрын
    • The problem is that you allocate the new dictionary and completely lose the old one since the Add method is pure so even tho the operation is not bad, since it is O(log n), the memory impact is big. That being said, mutation discussions on an immutable dictionary shouldn't be part of the discussion since the whole point is that you don't want it to be mutated, so the only thing that matters is read. And read speeds, because it is AVL, are O(log n) which is worse than O(1) and the difference is clearly observable.

      @nickchapsas@nickchapsas2 жыл бұрын
    • @@nickchapsas Isn't the point more to have value semantics? You can never have a shared reference to a mutable ImmutableDictionary, because any mutation returns a copy, and not the original instance, right? The tree is chosen to ensure mutation is still reasonably fast while requiring a copy (of the mutated nodes), and reading takes a hit but isn't horrible If you want an immutable dictionary with O(1) read times, you'd use ReadOnlyDictionary, and not ImmutableDictionary i think the name is kinda misleading to what a programmer expects of it (the point isn't to be immutable, it's to be mutable without allowing sharing a reference), but it accurately describes any individual instance as they are completely immutable after instantiating and you are *guaranteed* that if you store it, it will not be mutated unless you reassign the location you stored it to (whereas if you give someone a IReadOnlyDictionary it guarantees a consumer can't modify your dictionary, it will not be mutated when you pass it around, but if you receive one, it may be mutated between reads you perform)

      @sodiboo@sodiboo2 жыл бұрын
    • @@sodiboo My whole point is that the name is misleading and it doesn't convey how the implementation details change, which in return change the performance.

      @nickchapsas@nickchapsas2 жыл бұрын
    • @@nickchapsas Yeah, i can agree with that. It doesn't convey the implementation details and performance disadvantages, but it does convey the guarantee it makes (ReadOnly is something you only have read access to, but Immutable also says nobody else has mutating write access). I think for a lot of cases performance isn't *that* important and the semantics are more important, but yeah, it shouldn't be *that easy* to completely miss the differences internally as it is because it does matter

      @sodiboo@sodiboo2 жыл бұрын
  • Is there any reason why ConcurrentDictionary wouldn't just be the default (and hence be just called "Dictionary") if the performance is nearly identical to that of the existing Dictionary?

    @DanteDeRuwe@DanteDeRuwe2 жыл бұрын
    • The reason is performance. It is allocating more memory and operations take quite a bit longer (in the context of microseconds ofc) so if every little counts and thread safery isn't a concern, you would use Dictionary.

      @nickchapsas@nickchapsas2 жыл бұрын
  • Do you think it would be possible to add weak events to the C# language? so instead of subscribing with the += operator, you could subscribe with some other operator that would indicate to the language you wanted a weak subscription? be interesting to hear your thoughts on this. I'm guessing that it's not possible, else they would have already added it to the language. and thats why we have to use something else, like the the WPF weak event system? or maybe its to do with efficiency?

    @SirBenJamin_@SirBenJamin_2 жыл бұрын
    • Believe it or not the wpf weak event system isn't intended for wpf per se... Have a look at which assemblies those classes actually live in; iirc they aren't wpf related

      @tobyjacobs1310@tobyjacobs13102 жыл бұрын
    • To be honest, actually, Rx is a better solution. Especially since you can make observers self-disposing.

      @tobyjacobs1310@tobyjacobs13102 жыл бұрын
  • Almost offtopic related to a small mistake related to "natively" word being used: You said that "Hashtable.Synchronized existed natively", maybe it's just a small mistake with a word "natively" chosen poorly, but I'm stating my opinion anyway: I consider everything in C# not native because of it's virtual machine running IL being later JIT-ed into native code, it is not directly working with native code but indirectly working with it because of the JIT. As a reference: "Native code provides instructions to the processor that describe what tasks to carry out.", but nothing in C# is directly using native code, but it is using IL instead, degrading performance because of the Just In Time compilation required in order to convert the IL to native code.

    @alexandruchirita5780@alexandruchirita57805 ай бұрын
  • Interesting that your benchmarks showsDictionary with lock faster than a ConcurrentDictionary.... I wonder why.

    @ricardopieper11@ricardopieper11 Жыл бұрын
  • Immutability isn't free. Also, good luck implementing ImmutableDictionary functionality using Dictionary and IReadOnlyDictionary. I'm pretty sure you will get terrible performance.

    @RateTheQuad@RateTheQuad2 жыл бұрын
  • When I saw all those immutable classes I was so happy I started to use them everywhere. Then I found out about the implementation and got soooo sad. Now I don't use them anywhere and simply use the good IReadOnly interfaces. Done. If the caller dares to cast those instances, that's their problem. LOL

    @efrenb5@efrenb5 Жыл бұрын
  • Thanks but to be honest I don't think you did the title justice - I was expecting a discussion of real world use cases and the correct choice of dictionary for each, with the tradeoffs of each choice.

    @bokkeman123@bokkeman1232 жыл бұрын
    • Everything in the video can be adapted to real use cases. This is the reason why I show generic examples. Because if I show specific use cases you will think that this is the only problem. Showing a generic example allows each viewer to think how they can adapt it to their use cases

      @nickchapsas@nickchapsas2 жыл бұрын
  • I would love to see code a code analyzer that's just a configurable "ban" on certain types in a project. Then you could get compile time reminders to not use certain things, accompanied by alternative suggestions. Would really help with sticking to best practices and avoiding accidentally consuming footgun types.

    @lost-prototype@lost-prototype2 жыл бұрын
    • No, you will end up killing your own project. Please always take grain of salts on those video tutorials or blog posts. Pre-performance tuning by memorizing these kinds of language structures/features in mind, without any real experiences on large projects, could be extremely dangerous. Especially blindly listening to this video. Just take the video as an example of that language offers some cool features that I might want to use at some point. Stick to simple dictionary, quickly iterate your logic first without knowing any of others. At some point if you hit some perf issues you can update your basic dictionary easily, start to check those fancy Dicts from *official Doc* carefully, exanimate the *trade-off* because your basic structure is simple enough and has tons of flexibilities. If you are thinking too much and pre-perf tunes too much, it's hard to change. The worst case is that your pre-perf is the key perf issue and it's even faster without using any of fancy stuffs, because you has completely no idea about the trade-off behinds the languages/tools itself. All those performance checks in examples are mostly garbage because true performance issues is generally a result of combination of multiple choices/trade-off. As long as you don't write some random stupid codes cause O(n^2) that can be done by O(n), you are good to go. Real world projects sometimes can be complex that you might want to mix up different types of Dicts regardless languages/frameworks.

      @doc8527@doc85272 жыл бұрын
  • Interesting. Earlier we had a performance problem with ConcurrentDictionary that was solved with a regular Dictionary with locks. Your benchmark data showes the same

    @KjetilValoy@KjetilValoy2 жыл бұрын
    • Do you know why it is like that?I always thought that ConcurrentDictionary is faster than a "lock dictionary". I like to use ConcurrentDictionaries for caching data and I have been thinking that this is the best way to do it. But in this case you should write your own dictionary class with locked or what do you think?

      @intoverflow1106@intoverflow11062 жыл бұрын
    • Was it used on multiple threads? ConcurrentDictionary is tailored for usage with multiple threads. It will have more overhead than a regular dictionary on a single thread. It uses multiple locks internally so different parts can be accessed at the same time. It should be faster in a multi-threaded environment. If it's not, that would be weird indeed.

      @Grimlock1979@Grimlock19792 жыл бұрын
  • What about SortedDictionary?

    @fr3ddyfr3sh@fr3ddyfr3sh Жыл бұрын
  • Caption not available in your videos plz add

    @junaid9781@junaid97812 жыл бұрын
  • so the hashtable is completely pointless at this this time? How is it compared to Dictionary?

    @lordicemaniac@lordicemaniac2 жыл бұрын
    • Yeah don't use HashTable there is no point. Dictioanry is practically the same as HashTable since both keys and values will suffer from the same boxing problems

      @nickchapsas@nickchapsas2 жыл бұрын
    • HashTable is a leftover from C# 1.0. Generics were introduced in C# 2.0. Dictionary is just the generic version of HashTable. Just consider HashTable deprecated. The same goes for ArrayList. There are also non-generic versions of Queue, Stack and SortedList. Use the generic versions instead.

      @Grimlock1979@Grimlock19792 жыл бұрын
  • Dictionary has an O(n) for the add, and O(1) for the other operations.

    @haxi52@haxi522 жыл бұрын
    • No it’s not. Both add, search and delete are O(1) on average and O(n) for worst case

      @nickchapsas@nickchapsas2 жыл бұрын
    • @@nickchapsas well your benchmark data at 7:45 shows that: for 100 items it is 34.49us, for 1000 = 311.44us, for 10000 = 3214.10us. So looks like in reality it is still almost O(n), no?

      @germanpaskovskij776@germanpaskovskij7765 ай бұрын
  • How do you make it so that you can access the source of .NET libraries straight from your IDE?

    @JayBlackthorne@JayBlackthorne2 жыл бұрын
    • it's a feature of my IDE, Rider

      @nickchapsas@nickchapsas2 жыл бұрын
  • 420 viewers while I was watching... Interesting random number there

    @evanboltsis@evanboltsis2 жыл бұрын
  • I've recently discovered the HybridDictionary

    @wizardofboz76@wizardofboz762 жыл бұрын
  • Hey Nick, Which extension you are using to see the built in class code file and complete structure using F12 or Go to Definition.

    @addyrocking86@addyrocking862 жыл бұрын
    • It's the same thing. Rider just does that on F12/Go to Definition.

      @nickchapsas@nickchapsas2 жыл бұрын
  • I wish C# supported the 'const' keyword the way C++ does. This would make all these weird "...AsReadOnly...()" methods and excess code required to make things readonly. Don't want something to be mutable outside of a class? Declare it const.

    @tomwimmenhove4652@tomwimmenhove4652 Жыл бұрын
  • Oh, be careful with this expectations about Big-O complexity estimations. Yes, something with O(n) complexity sounds great in theory. But this hides the actual cost of the static factors in the algorithm. I mean, what good is your great O(n) or O(n*log n) algorithm if there is some static cost for the calculation which is not expressed in the powers? Not so long time ago, I worked on an application with kinda HUGE in-memory database. Consisting of many data lookup tables, typically having quite long strings as keys. In the end, for most cases SortedDictionary was used for performance reasons. Why? Because Dictionary or HashTable always need to run a hash function on the entire string. Lots of CPU cycles every time in order to do just that, please the collision handling afterwards within the hash table storage. On the other hand, if the typical pattern for the contents of your keys indicates that they are very dispersed, then a tree-based structure (AVL or RedBlack or whatever is used by SortedDictionary ATM) can make the decision to navigate in the tree after reading only the first bytes of the string contents.

    @DuRoehre90210@DuRoehre90210 Жыл бұрын
  • So there is no performance benefit to using ImmutableDictionary? I did not expect that. Would using int keys instead of strings have any sort of perf difference at least?

    @MsKpg@MsKpg2 жыл бұрын
    • No you actually lose performance. You are better of using a normal Dictionary and just agree to treat it as immutable or even better to use a ReadOnlyDictionary. Value types in general are a bit faster as keys in hashtables than reference types but it's not something you should be really thinking. Ofc this is only relevant if what you are after is a read only dictionary.

      @nickchapsas@nickchapsas2 жыл бұрын
    • @@nickchapsas Have you looked at the differences in performance with ImmutableSortedDictionary? Its implementation is different than the non-sorted version.

      @kylewascher2130@kylewascher21302 жыл бұрын
  • I have to remember to never use the dictionary type I never knew existed. Done

    @raztubes@raztubes2 жыл бұрын
  • The brackets operator on concurrentDictionary is actually not thread safe

    @yarondavid@yarondavid2 жыл бұрын
    • Do you mean upon initialization?

      @nickchapsas@nickchapsas2 жыл бұрын
  • Did you thanked David Fowler for the inspiration?

    @SilentTremor@SilentTremor2 жыл бұрын
    • Literally in the first 30 seconds of the video

      @nickchapsas@nickchapsas2 жыл бұрын
  • Wait, so I shouldn't be using Hashmap?

    @richardrisner921@richardrisner9212 жыл бұрын
  • please add subtitle

    @masslooo2003@masslooo20032 жыл бұрын
  • :D i've never used ImmutableDictionary right until *yesterday*, actually when i had a use case for it and figured "it _must_ be faster, right?" Thanks! Need to revert that again

    @aremes@aremes Жыл бұрын
  • 5:56 Mmmmmmmm??!

    @jr.BoarOfGold@jr.BoarOfGold Жыл бұрын
  • "420 is always a random number" heh

    @mathboy8188@mathboy81882 жыл бұрын
  • You look great for your 69 😀 great stuff, didn't know about immutable dictionaries behavior

    @b0rkes@b0rkes2 жыл бұрын
  • “Hello, *mumble mumble intro*, today..”

    @deandre1988@deandre19882 жыл бұрын
    • Classic intro on brand

      @nickchapsas@nickchapsas2 жыл бұрын
  • A LIKE for using RIDER :)

    @SuperBadGPT@SuperBadGPT2 жыл бұрын
  • So really there's only two Dictionary types. Dictionary and ConcurrentDictionary. Hashtable is obsolete. Dictionary does the exact same thing. ImmutableDictionary is very niche. The chances are that you are better off either: - Using const/readonly fields/properties. - Initialise a ReadOnlyDictionary from a JSON (or similar) file.

    @fat-freeoliveoil6553@fat-freeoliveoil65532 жыл бұрын
  • How did you drill down to the concurrent dictionary code?

    @sepbla178@sepbla1782 жыл бұрын
  • So never use ImmutableDictionary, what would be there use case if it performs worse all the time? What about ReadOnlyDictionary? Say I pre-initialize a Dictionary that from then will never change. What might be the best option to use? I am surprised that the Get operation (dict[key]?) is so slow for it, I thought it would be faster. Or was that something else? I have to to join the Discord...

    @mcdev6868@mcdev6868 Жыл бұрын
  • @nick Since we're talking about collections here, can we talk about how List, Set etc. in C# do *NOT* override GetHashCode() and Equals()? I could hardly believe my eyes when I first saw that. But indeed, new List { "a" }.Equals(new List {"a"} ) ... WILL return false in C#. Just what on earth were they thinking?

    @AlanDarkworld@AlanDarkworld2 жыл бұрын
    • It makes sense since they are different objects with different references.

      @nickchapsas@nickchapsas2 жыл бұрын
    • @@nickchapsas true, they're different memory addresses. But isn't it the very purpose of Equals to determine equality based on content and semantics, rather than memory addresses? I know for a fact that the same code on the JVM will return true.

      @AlanDarkworld@AlanDarkworld2 жыл бұрын
    • @@AlanDarkworld no, that is a feature of higher level languages like JavaScript or python. You compare value types by value and reference types by reference/pointer. That's the way it is in C/C++. Changing the rules arbitrarily just makes it harder to understand how it's actually working under hood. Without the difference, it would be easy to have unexpected situations where two references are comparing as equal but changing a value on a reference in one location does not change it in the other. The new record class in C# has the type of behavior you are thinking of.

      @filiecs3@filiecs32 жыл бұрын
  • 69. Just a random age. Mmhmm.

    @kmcdo@kmcdo2 жыл бұрын
  • Then basically all are almost the same in performance in add, get and update, except inmmutable that sux

    @anonimxwz@anonimxwz2 жыл бұрын
  • never understood immutable objects. If you dont want things to change, dont change them if anything gets reused and distributed over such a large space that you cannot guarantee it, you need to modularize better in the end all you should offer are some safe objects or an api that cannot be "messed up" easily from the outside many languages have ways to "hack" immutable objects and change them anyway and at that point a mere "this property is not meant to be changed" warning is enough

    @Maric18@Maric182 жыл бұрын
  • 69 random age haha

    @samuelgrahame3617@samuelgrahame36172 жыл бұрын
  • 420 was here first.

    @djgiel4life@djgiel4life2 жыл бұрын
  • So why ImmutableDictionary exists at all if it worse than normal dictionary?

    @henson2k@henson2k Жыл бұрын
  • Just use java

    @TheMainManNorthOfEquator@TheMainManNorthOfEquator2 жыл бұрын
    • lol no

      @nickchapsas@nickchapsas2 жыл бұрын
  • More "var"... it's not js

    @ether626@ether6262 жыл бұрын
  • Sounds like you got the issue narrowed down from A-Z

    @Eryklok@Eryklok2 жыл бұрын
  • I thought that the ConcurrentDictionary.AddOrUpate did not grab a lock.

    @giszTube@giszTube2 жыл бұрын
KZhead