Generic C# Library Design

# DotGNU Portable.Net FAQ

Rhys Weatherley, rweather@southern-storm.com.au.
Last Modified: $Date: 2003/12/23 22:07:07 $

Copyright © 2003 Southern Storm Software, Pty Ltd.
Permission to distribute unmodified copies of this work is hereby granted.

## Introduction

This document describes the design of Portable.NET's Generic C# collection library. The library is distributed under the terms of the General Public License (GPL) with the linking exception.

The library was designed to have a similar "flavour" to the existing non-generic C# collections, with some ideas borrowed from the C++ Standard Template Library (STL), and the Java 2 Collections library.

## Conventions

Notations such as `ArrayList<T>` are used to indicate generic classes; whereas notations such as `ArrayList` are used to indicate the traditional non-generic classes.

## General design considerations

Here are some examples of the problems in the existing non-generic collection classes:

1. It is possible to create read-only, fixed-size, and synchronized `ArrayList`'s, but only synchronized `Hashtable`'s.
2. Common algorithms, such as sorting and searching, must be implemented in every concrete list implementation, when it would make more sense to have a common utility method that takes an `IList`.
3. Ugly hacks, like wrapping an `IList` inside an `ArrayList`, to get around the algorithm limitations.
4. Enumerators are read-only, failing if the underlying collection is modified. This makes it difficult to implement algorithms that require modify in-place, or the removal of items during traversal.
5. Confusion between abstract and concrete implementations in some cases. e.g. there is a `Queue` class, but no `IQueue` interface. So, it isn't easy to replace an array based queue with a linked list based queue.
6. Functionality is overridden through `virtual` methods, usually to allow read-only or type-safe wrapping. This can make the base implementation less efficient, due to the overhead of virtual method calls that will rarely point at anything except the base implementation.
7. `IsReadOnly` and `IsFixedSize` are common collection traits like `IsSynchronized`, but appear in subinterfaces instead of `ICollection`.

To address these problems, we have the following design constraints:

1. Read-only, fixed-size, and synchronized functionality are provided with separate decorator classes, not as part of the concrete implementations. e.g. `ReadOnlyList<T>`.
2. Common algorithms are ejected to the `Algorithm` utility class as `static` generic methods.
3. Concrete classes only implement interfaces - they never implement other utility functions beyond that.
4. Iterators are introduced to replace enumerators, and support in-place removal. List iterators also support traversal backwards through a list and in-place modification of the current item.
5. Concrete classes always implement at least one abstract interface representing a useful data structure (list, queue, stack, etc).
6. Concrete classes are `sealed`. Modified functionality is provided using decorators.
7. Common collection traits are placed into `ICollection<T>`.

We eschew the use of abstract base classes for implementations. e.g. Java 2's `AbstractCollection`. This is typically used to implement common utility methods (e.g. `addAll()` for copying one collection into another). Such utility methods are placed into the `Algorithm` class in our implementation.

An equivalent of the existing `CollectionBase` class is not needed in this implementation. It is typically used to enforce type safety constraints, which the generic language facilities are already taking care of for us. `CollectionBase` is also used to get notification of insertions, removals, etc. This can be accomplished using decorator classes instead.

> Notes: the design of iterators is based on the Java 2 collection classes. The idea of ejecting algorithms and utility methods out of the concrete classes is borrowed from the C++ Standard Template Library.

## Collection interfaces

`ICollection<T>`
  Base interface for all collections.
`IDeque<T>`
  The collection is organised as a deque (double-ended queue).
`IDictionary<KeyT, ValueT>`
  The collection is organised as a dictionary, mapping keys to associated values.
`IIterable<T>`
  The collection can be iterated over.
`IList<T>`
  The collection is organised as a list, ordered on index. The `IsRandomAccess` property can be used to determine if the indexer implements constant-time lookups (e.g. `ArrayList<T>`) or non constant-time lookups (e.g. `LinkedList<T>`).
`IQueue<T>`
  The collection is organised as a FIFO queue, where additions occur at one end, and removals from the other.
`ISet<T>`
  The collection is organised as a set. Each value will occur at most once in the set.
`IStack<T>`
  The collection is organised as a stack, where additions and removals occur at the same end.

## Iterators

`IIterator<T>`
  Provides a counterpart to the non-generic `IEnumerator` interface, with the addition of a `Remove` method. This method is used to remove the current item in the iteration in such a way that traversal can continue naturally.
`IListIterator<T>`
  Extends `IIterator<T>` with the ability to traverse backwards through a list, to get the current position by index, and to modify the current item in-place.
`IDictionaryIterator<T>`
  Extends `IIterator<T>` with properties that extract the key and value components, and modify the value of the current item in-place. There is no counterpart to the `IDictionary.Entry` property, because it is identical to `Current`.

If an iterator operation is called after the underlying collection has been modified, the behaviour is undefined. It may operate correctly, it may throw an exception, or it may appear to operate correctly but actually do something else. The only guarantees given are with respect to modifying `Current` and calling `Remove` on the iterator.

## Utility interfaces

`IComparable<T>`
  Provides a counterpart to the non-generic `IComparable` interface. Objects that implement this interface can be compared.
`IComparer<T>`
  Provides a counterpart to the non-generic `IComparer` interface. It compares two values of type `T`.
`IHashCodeProvider<T>`
  Provides a counterpart to the non-generic `IHashCodeProvider` interface. It takes a value of type `T` and returns a hash code, suitable for use in classes such as `Hashtable<T>`.
`ICapacity`
  Provides an interface to get or set the capacity of a collection. Implemented by classes like `ArrayList<T>` that use an array to implement growable data structures.

## Concrete implementations

`ArrayList<T>`
  Implementation of an `IList<T>`, organised as an array.
`ArrayQueue<T>`
  Implementation of an `IQueue<T>`, organised as an array.
`ArrayStack<T>`
  Implementation of an `IStack<T>`, organised as an array.
`Hashtable<KeyT, ValueT>`
  Implementation of an `IDictionary<KeyT, ValueT>`, organised as a hash.
`LinkedList<T>`
  Implementation of an `IList<T>`, organised as a doubly-linked list. This class also implements `IDeque<T>`, `IQueue<T>`, and `IStack<T>`.
`ListSet<T>`
  Implementation of an `ISet<T>` on top of an underlying `IList<T>` object. By default, a `LinkedList<T>` object is used.
`SinglyLinkedList<T>`
  Implementation of an `IList<T>`, organised as a singly-linked list. This class also implements `IQueue<T>` and `IStack<T>`.
`TreeSet<T>`
  Implementation of an `ISet<T>` as a balanced binary tree.
`TreeDictionary<KeyT, ValueT>`
  Implementation of an `IDictionary<KeyT, ValueT>` as a balanced binary tree.

## Decorators

`FixedSizeCollection<T>`
  This class, and its descendents, are used to wrap up collections to make them appear to be fixed-size to callers. Any attempt to modify the size of the collection will result in an `InvalidOperationException`.
`ReadOnlyCollection<T>`
  This class, and its descendents, are used to wrap up collections to make them appear to be read-only to callers. Any attempt to modify the contents of the collection will result in an `InvalidOperationException`.
`SynchronizedCollection<T>`
  This class, and its descendents, are used to wrap up collections to synchronize access from multiple threads. The concrete collection classes are not safe to use simultaneously from multiple threads unless they are wrapped up in this fashion.

There are decorator classes for collections, deques, dictionaries, lists, queues, sets, and stacks. They all follow the above style.

## Adapters and wrappers

Sometimes it can be useful to use a generic collection with an existing API that expects a non-generic collection, or to use an existing non-generic collection with a new API that expects a generic one. The following classes are provided for enabling interoperation between generic and non-generic libraries:

`CollectionAdapter<T>`
  This class wraps a generic `ICollection<T>` and exports the non-generic `ICollection` interface.
`CollectionWrapper<T>`
  This class wraps a non-generic `ICollection` and exports the generic `ICollection<T>` interface.
`ComparableAdapter<T>`
  This class wraps a generic `IComparable<T>` and exports the non-generic `IComparable` interface.
`ComparableWrapper<T>`
  This class wraps a non-generic `IComparable` and exports the generic `IComparable<T>` interface.
`ComparerAdapter<T>`
  This class wraps a generic `IComparer<T>` and exports the non-generic `IComparer` interface.
`ComparerWrapper<T>`
  This class wraps a non-generic `IComparer` and exports the generic `IComparer<T>` interface.
`DictionaryAdapter<KeyT, ValueT>`
  This class wraps a generic `IDictionary<KeyT, ValueT>` and exports the non-generic `IDictionary` interface.
`DictionaryWrapper<KeyT, ValueT>`
  This class wraps a non-generic `IDictionary` and exports the generic `IDictionary<KeyT, ValueT>` interface.
`DictionaryEnumeratorAdapter<KeyT, ValueT>`
  This class wraps a generic `IDictionaryIterator<KeyT, ValueT>` and exports the non-generic `IDictionaryEnumerator` interface.
`DictionaryEnumeratorWrapper<KeyT, ValueT>`
  This class wraps a non-generic `IDictionaryEnumerator` and exports the generic `IDictionaryIterator<KeyT, ValueT>` interface.
`EnumerableAdapter<T>`
  This class wraps a generic `IIterable<T>` and exports the non-generic `IEnumerable` interface.
`EnumerableWrapper<T>`
  This class wraps a non-generic `IEnumerable` and exports the generic `IIterable<T>` interface.
`EnumeratorAdapter<T>`
  This class wraps a generic `IIterator<T>` and exports the non-generic `IEnumerator` interface.
`EnumeratorWrapper<T>`
  This class wraps a non-generic `IEnumerator` and exports the generic `IIterator<T>` interface.
`HashCodeProviderAdapter<T>`
  This class wraps a generic `IHashCodeProvider<T>` and exports the non-generic `IHashCodeProvider` interface.
`HashCodeProviderWrapper<T>`
  This class wraps a non-generic `IHashCodeProvider` and exports the generic `IHashCodeProvider<T>` interface.
`ListAdapter<T>`
  This class wraps a generic `IList<T>` and exports the non-generic `IList` interface.
`ListWrapper<T>`
  This class wraps a non-generic `IList` and exports the generic `IList<T>` interface.

As can be seen, we use "`*Adapter`" classes to wrap generic collections for non-generic use, and use "`*Wrapper`" classes to wrap non-generic collections for generic use.

## Miscellaneous classes

`Algorithm`
  Provides a large number of generic utility methods for manipulating collections according to various algorithms (sort, search, etc).
`BuiltinComparer<T>`
  Implementation of `IComparer<T>` which uses the builtin "`<`" and "`>`" operators to perform the comparison. This is only useful when `T` is a primitive numeric type.
`Comparer<T>`
  Implementation of `IComparer<T>` which uses `IComparable<T>` and `IComparable` to perform the comparison.
`Complex<T>`
  Implementation of a complex number type, based on an underlying numeric type `T`.
`DictionaryEntry<KeyT, ValueT>`
  A value type that contains a key/value pair for use with dictionary collections and iterators.
`Predicate<T>`
  Delegate that takes a single argument of type `T` and returns `true` if some predicate condition has been satisfied by the argument.
`RangeList<T>`
  Wraps up an `IList<T>` to access a sub-range.
`ReverseIterator<T>`
  Wraps up an `IListIterator<T>` to reverse the direction of traversal.
`TreeBase<KeyT, ValueT>`
  Utility base class for `TreeSet<KeyT>` and `TreeDictionary<KeyT, ValueT>`. Not recommended for direct use by programmers.

Copyright © 2003 Southern Storm Software, Pty Ltd.
Permission to distribute unmodified copies of this work is hereby granted.