08 September 2006

I honestly thought I was done with this topic but as it turns out I missed something. I stated firmly that "currently, in C#, we are stuck with the cast" but I was wrong. One of the great things about working at Microsoft is the people you can interact with. In back burner researching a definitive answer to Hallvard's question to my post of why linked list LinkedList<T> cannot be written,

  class LinkedList<T>: LinkedList<T, LinkedList<T>.Node> { }

I asked Andrew Kennedy to look at my page. I like talking to Andrew; I learn at least one new thing every time we talk. This was certainly no exception. He quickly pointed out something that was staring me squarely in the face but I missed entirely, folding my implementation of DoubleLinkedList<T> with DoubleLinkedList<T, N> and closing the node type directly will remove the cast. In other words, DoubleLinkedList<T> can be written without casts as,

    class DoubleLinkedList<T>: LinkedList<T, DoubleLinkedList<T>.DoubleNode>,
        IDoubleLinkedList<T> {

        public class DoubleNode: Node {
            DoubleNode _previous;

            public override DoubleNode Next {
                get {
                    return base.Next;
                }
                set {
                    base.Next = value;
                    value._previous = this;
                }
            }

            public DoubleNode Previous { get { return _previous; } }
        }

        public IEnumerable<T> Backwards {
            get {
                if (Last != null) {
                    DoubleNode current = Last;
                    do {
                        yield return current.Data;
                        current = current.Previous;
                    } while (current != Last);
                }
            }
        }
    }

which closes the node parameter instead of leaving it open. This is one of those head-slapping, "how stupid of me" moments like when someone points out that "you know, if you would have pushed the other pawn instead, you would have had checkmate in three moves." You can see that this is a straight forward application of the requires clause version (declaring it to be DoubleNode instead of requiring it). In my zest to introduce the concepts of the "this type" from LOOM and the requires clause from Scala, I missed what should have been obvious. Silly me.

This solution has the limitation that you cannot derive something like TripleLinkedList<T> from DoubleLinkedList<T> so my example still holds some water (TripleLinkedList<T, N> can be derived from DoubleLinkedList<T, N>) but it is not nearly so compelling. I still think that one of the two features would be very useful but I need a much better motivating example.

While I still don't have a definitive answer to Hallvard's question, I picked up this gem along the way. Not bad so far.



blog comments powered by Disqus