I’m writing an immutable binary tree class where all of the methods (Insert, Remove, RotateLeft, etc) return a new instance of a tree instead of modifying it in place.
I’m going to be creating lots of different implementations of tree: Avl tree, red-black tree, splay tree, etc. I have the following:
public class AbstractBinaryTree<TreeType, T>
where TreeType : AbstractBinaryTree<TreeType, T>
where T : IComparable<T>
{
protected abstract TreeType CreateNode(TreeType left, T value, TreeType right);
protected abstract T Value { get; }
protected abstract TreeType Left { get; }
protected abstract TreeType Right { get; }
protected abstract bool IsNil();
public TreeType Insert(T item)
{
if (this.IsNil())
{
return CreateNode(this, item, this);
// ^ doesn't compile, can't convert type
// AbstractBinaryTree<TreeType, T> to type TreeType
}
else
{
int compare = item.CompareTo(this.Value);
if (compare < 0)
{
return CreateNode(this.Left.Insert(item), this.Value, this.Right);
}
else if (compare > 0)
{
return CreateNode(this.Left, this.Value, this.Right.Insert(Value));
}
else
{
return this;
// ^ doesn't compile, can't converrt type
// AbstractBinaryTree<TreeType, T> to type TreeType
}
}
}
}
The idea here is that AbstractBinaryTree is a tree node — more than that, it is the same type as TreeType. If I can get the above base class working correctly, then I can write something like this:
public class AvlTree<T> : AbstractBinaryTree<AvlTree<T>, T>
{
public override AvlTree<T> Insert(T item) { return Balance(base.Insert(item)); }
}
so that my Insert method returns AvlTree<T> instead of AbstractBinaryTree<AvlTree<T>, T>. However I can’t even get this far because the base class doesn’t compile.
How do I pass an instance of AbstractBinaryTree into a method which takes a type TreeType?
I don’t really have an answer – just a few hints that may be useful. I think this would work in a language that has a concept called self types (I can’t find and good site to link!). Anyway, a self type means that you can declare an abstract base class (say
A) and it can have a method that returns the self type. When creating an inherited class (sayB) the uses of the self type will refer toB(which is interesting, because the base class didn’t know about this class). For C# 4 fans, the self type is covariant.Anyway, you could try searching for a way to emulate self types in C# using generics…
Another pointer is to an article that I’ve seen some time ago. As far as I remember, it used generics in a similar way as you do, so maybe it can give you some hint how to solve the problem.