Thursday, July 08, 2004 6:58 PM
pgolde
Design philosophy
An email correspondent writes:
I was wondering to what degree Power Collections is going to be alternate implementations of existing BCL concepts, or if you're going to implement new interfaces or refactor existing ones. For example, Set, Bag, and OrderedCollection semantics makes sense independent of Tree-backed implementations, and when you provide sorted implementations then bidirectional enumerators become very convenient.
It's an excellent question, and maybe I can provide some initial thoughts on my design philosophy for Power Collections, and how it relates to the .NET 2.0 BCL as it exists.
My general precepts are "augment, not replace", and "work as seamlessly as possible with the existing BCL". What exactly do I mean by those statements? Here are some examples of how I think these ideas apply:
"Augment, not replace". What we're trying to do with Power Collections is provide additional collections "stuff" to add on to what is already there. I'm not really looking to provide another array-based list or hash-table based dictionary; the existing List and Dictionary may not be perfect, but they fill this space ably enough, and people already understand and use them. While I'm sure I could find some interesting methods that could be added to these classes (and some that should be removed!), I don't think the benefit would be sufficient to ask people to learn a whole new class.
When we're done, you should be able to write:
using System.Collections.Generic;
using Wintellect.PowerCollections;
And begin using collections from both sets, without noticing many problems. One thing I really want to avoid is creating any type names that duplicate existing type names in the BCL, since that will cause compiler errors when you use them.
By “work as seamlessly as possible with the existing BCL”, I mean that Power Collections will embrace the existing types, interfaces, and design principles of the current BCL, and prioritize conformity higher than what I might think is the “best possible”. For example, the collections in PowerCollections will implement the existing IEnumerable, ICollection, IList, IDictionary... interfaces, both generic and non-generic, even though there may be apparent warts in those interfaces. I may lobby for changes while changes are still possible, but in the end, we'll live with (and learn to love) what we've got.
Will Power Collections introduce any new interfaces? Probably some, but generally I think new interfaces need to be introduced sparingly, and with forethought. A good interface is one that is implemented by a number of different types, and that encapsulates a useful, generalized, simple piece of functionality that clients want to use on its own.
IFormattable is a example of a great interface: it is simple, easy to implement, and encapsulates a very useful piece of functionality for use by String.Format and similar functions.
Some people advocate a design and coding philosophy of “code only to interfaces, not to implementations”. In the extreme form of this style, class names only appear after a “new”, and all other type names are interfaces. You always write:
IList myList = new List();
instead of:
List myList = new List();
Furthermore, List doesn't expose any methods that aren't in IList.
I disagree with this style. Taken to its logical conclusion, it forces a doubling of the number of types in the library, which significantly impedes comprehensibility and understanding with little concrete benefit to the user. Would there be any point to having an IStringBuilder as well as a StringBuilder?
This is not to say that IList is not a useful interface; it certainly is. But it is useful precisely because it only contains the minimum amount of “list“ like functionality, and therefore can be easily implemented by many different lists in the system. If an interface has only one useful implementing class, then it probably shouldn't exist in the first place.
What do you all think?