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.