Chuckle. What happens when those wonderful assumptions you trust break down? It can be kind of amusing some times.
So I'm stress testing Assets this evening, and I import 1000 of the Famfamfam icons. And it appears to just lock up. I break into it, it's doing reasonable work. A long time later, it gets done. A really really really really really long time later. Let's ramble around for a minute.
When to use what kind of Collection? Well, one of the reasons for using a Set, especially with a big collection, is that it provides fast removal of items, since it's a hash lookup, instead of a linear search.
What would you expect the following code to do?
methods := Object getMethodDictionary asSet.
methods removeAll: methods copy.
This runs quite quickly. You can use values instead of asSet, and it's still pretty snappy. If you measure it though, using an asSet is almost 3x faster. For this case it's fast enough either way, I just happend to use asSet, because I liked the "singular" semantics of it.
Ok, now replace 'Object' with 'ToolbarIconLibrary class' in that code snippet. Run the code again. If you time it... a singular pass using asSet will now take 910 ms. A singular pass using values will take 5. What happened?! We've gone from being nearly 3x faster to 200 times slower. For greater enjoyment try it with your assets class that you added 1000 icon methods to. The numbers? 15 ms for the values. 242 seconds for the asSet. You do the math.
The problem in these "slow" cases is that these classes are stuffed primarily with a special subclass of CompiledMethod called AnnotatedMethod. Every time you add any sort of <method tag> (what some call "pragmas") to a method, the compiler creates this subclass variant of CompiledMethod which has instance variables to store the method tag meta data in.
Upon further inspection of MyAssets class, I found that amongst the 1000 methods I had added... there were exactly 3 unique hash values. I assumed a poorly written hash method. Everyone knows that when you override the = method, you're supposed to provide a hash function as well, right? Right? RIGHT? If you don't, the approaching morale of the story is please learn it now. There is no poorer hash method than the one you didn't write.
If we write a trivial hash method for AnnotatedMethod
^super hash bitOr: self attributeMessages
we get respectable performance again. Always write a hash method. I'm sure
My Good Friend Andres Valloud will be able to add this to his hash work he's doing. And I'm sure he'll actually write a better one than my trivial implementation.