The original Ioke implementation uses interfaces in place of classes when referring to collections. This is standard in the Java world, and wasn’t something I explicitly designed in, although it did make things very convenient in some cases, when I switched implementation strategies, or wanted to add ordering to to a dictionary. No references changed, just the pieces creating new instances. Very nice.
When I started the Ioke port to the CLR, I assumed that the collections work the same way in .NET, especially since there at first glance seem to be several interfaces for collections.
Boy was I wrong.
My first piece of unease came when I realized that there was no specific Set interface, so I ended up using ICollection instead. That works, but I use interfaces to capture intent, and in the specific case the intent to have a set was extremely important.
The next problem cropped up when I realized there was no unification of generic interfaces and non-generic interfaces. This is obviously not possible since the CLR uses reified generics, but I still hadn’t actually thought about it. This turned out to be extremely annoying in some cases – especially with regards to ordered collections. OrderedDictionary is more or less a counterpart of LinkedHashMap in Java – it keeps track of insertion order and will yield the entries in that order when iterating. This can be highly useful functionality. I wanted it for representing cells, like I do in the Java implementation. Problem is, cells is a collection that should be generic – but OrderedDictionary is not generic. Sigh. I could of course implement my own versions of these, but the point of a collections library is that I shouldn’t HAVE to do that.
The next item in the case against .NET happened when I started getting strange exceptions when I called ICollection.Add with a HashSet in that reference. The objects sent to Add shouldn’t have been any problem, but I still got (but only sometimes) exceptions saying my object was out of range, or something like that. I tried different things, but nothing solved it. At that point I noticed that HashSet<T> had two different implementations of Add. One regular, and one explicit ICollection.Add implementation. I couldn’t figure out if they were the same or not, but since it was listed separately, I thought they might be different. So I changed the original reference from ICollection<T> to HashSet<T> … And the error went away. I’m not sure if this is a bug in Mono, or .NET, or something else really weird, but that’s the behavior I saw.
And that brings up my main point. You can’t really use many of the interfaces in the .NET core library. Interfaces are about hiding implementation details and expressing intent – but when they don’t work, or are mismatched like they are in the .NET collections, this is impossible to do well. Bringing in explicit interface implementations that do different things depending on called with the interface as reference or not, only makes the situation even harder.
The story has a sad ending. I reverted to using explicit implementation classes for all references to collections. This sucks in many ways.