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 (say B ) the uses of the self type will refer to B (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 The Expression problem revisited by Mads Torgersen (now in the C# team!).
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 (say B) the uses of the self type will refer to B (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. The Expression problem revisited by Mads Torgersen (now in the C# team!).
1: very interesting :) Although C# doesn't support this out of the box, its very easy to simulate with abstract classes. For example, base class A where T : A can have an abstract method T Self(), and a derived class B : A can implement the method as override B Self() { return this; }. I actually have an implementation of this sort of strategy here (pastebin.Com/PussQDmN), and it works perfectly exactly as advertised.
– Juliet Mar 11 '10 at 4:30 +answer: emulating self-types with generics is ultimately the solution I settled on :) – Juliet Mar 25 '10 at 17:16 Be careful with evil dogs, though. – Jordão Jun 21 at 16:41.
Use AbstractBinaryTree public abstract class AbstractBinaryTree where TreeType : AbstractBinaryTree where T : IComparable { protected abstract TreeType CreateNode(AbstractBinaryTree left, T value, AbstractBinaryTree right); protected abstract T Value { get; } protected abstract TreeType Left { get; } protected abstract TreeType Right { get; } protected abstract bool IsNil(); public virtual AbstractBinaryTree Insert(T item) { if (this.IsNil()) { return CreateNode(this. Left, item, this. Right); // ^ doesn't compile, can't convert type // AbstractBinaryTree to type TreeType } else { int compare = item.
CompareTo(this. Value); if (compare 0) { return CreateNode(this. Left, this.
Value, this.Right. Insert(Value)); } else { return this; // ^ doesn't compile, can't converrt type // AbstractBinaryTree to type TreeType } } } } public class AvlTree : AbstractBinaryTree where T : IComparable { public override AbstractBinaryTree Insert(T item) { return base. Insert(item); } } With Balance() to cast private AvlTree Balance(AbstractBinaryTree item) { return (AvlTree)item; } public override AbstractBinaryTree Insert(T item) { return Balance(Insert(item)); }.
Where T : AbstractBinaryTree, T>, IComparable in the AvlTree should probably just be where T : IComparable – Tanzelax Mar 10 '10 at 4:23 Also with private AvlTree Balance(AbstractBinaryTree, T> tree);, you can have the desired public override AvlTree Insert(T item) – Tanzelax Mar 10 '10 at 4:29 You will have to cast the return from Insert() to get to the more specific type. Its a strange one... – CRice Mar 10 '10 at 4:30 Good point Tanzelax – CRice Mar 10 '10 at 4:33 Her desired override was return Balance(base. Insert(item));, so her Balance function can theoretically act on an AbstractBinaryTree and return an AvlTree (since CreateNode returns TreeType, and this is also TreeType in this case).
– Tanzelax Mar 10 '10 at 4:35.
Oh wow, I make things too hard for myself, but in any case the solution is really super simple: AbstractBinaryTree already contains a Left, Value, and Right property, so I can just create a copy of the current node using CreateNode(this. Left, this. Value, this.
Right) instead of trying to return this: public abstract class AbstractBinaryTree where TreeType : AbstractBinaryTree where T : IComparable { protected abstract TreeType CreateNil(); 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 virtual TreeType Insert(T item) { if (this.IsNil()) { // can't return 'this', so just creating a new nil node TreeType nil = CreateNil(); return CreateNode(nil, item, nil); } else { int compare = item. CompareTo(this. Value); if (compare 0) { return CreateNode(this.
Left, this. Value, this.Right. Insert(Value)); } else { // can't return 'this', so just creating a new node with a // copy of the same values return CreateNode(this.
Left, this. Value, this. Right); } } } } public class AvlTree : AbstractBinaryTree { public override AvlTree Insert(T value) { return Balance(base.
Insert(value)); } } The implementation of AvlTree works out beautifully because we recursively insert into the tree on the way down, and balance the tree as the callstack unwinds. If anyone can suggest a way that let's me reuse this instead of allocating a new object with a copy of its values, I'd like to hear it, but for right now this seems to work.
Great! Yes it seemed to want either 'CreateNode' or 'this', which was making it difficult. – CRice Mar 10 '10 at 5:26 This is quite slick.
:) Also, if you want to get rid of the tree copies, if (this.IsNil()) { return CreateNode(this. Left, item, this. Right); } should be fine (assuming Nil.
Left is Nil), which would also get rid of the need for CreateNil(), and you could probably just as cast this even if you're really paranoid about type safety on your cast return to not (usually) need the copy on insert equal... return (this as TreeType)? CreateNode(this. Left, this.
Value, this. Right) – Tanzelax Mar 10 '10 at 9:04.
I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.