Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GenericTree<T> can't be properly extended #30

Open
bretthysuik opened this issue Dec 22, 2014 · 3 comments
Open

GenericTree<T> can't be properly extended #30

bretthysuik opened this issue Dec 22, 2014 · 3 comments

Comments

@bretthysuik
Copy link

InsertItem and RemoveItem can't be properly overridden in a derived class because Add returns a GeneralTree<T> instance. Consumers of the derived type have to explicitly cast the GeneralTree instance returned by Add to their derived type in order for the overridden functionality to be called.

Example:

public class DerivedGeneralTree<T> : GeneralTree<T>
{
    protected override void InsertItem(int index, GeneralTree<T> item)
    {
        // Do something special...
    }

    protected override void RemoveItem(T item)
    {
        // Do something special...
    }
}
var derivedTree = new DerivedGeneralTree<string>("root");
// Returns GeneralTree<T>! Overridden code won't be called unless consumer 
//  explicitly casts to DerivedGeneralTree<T> each and every time!
GeneralTree<T> a = derivedTree.Add("a");

I hate to say it, but the entire GeneralTree<T> abstraction is broken because of all the ITree<T> explicit implementations and the usage of GeneralTree<T> in method signatures instead of the base interface.

Declaring var derivedTree as an ITree<string> isn't useful because you lose out on all the nice methods in GeneralTree<string>....

@SimonCropp
Copy link
Member

@bretthysuik so how would you fix this?

@bretthysuik
Copy link
Author

I haven't looked into the other tree implementations so I don't know if the following suggestions would break something outside the scope of GeneralTree<T> and ITree<T>:

ITree

  • Add the following property and methods:
ReadOnlyCollection<ITree<T>> Children { get; }

ITree<T> Add(T item);

BreadthFirstTraverse(IVisitor<ITree<T>> visitor);

DepthFirstTraverse(OrderedVisitor<ITree<T>> visitor);

I find IVisitor<ITree<T>> much more useful than IVisitor<T> because it allows me access to more information during traversal.


GeneralTree

  • Eliminate as much explicit interface implementations as possible.
  • Reference the base ITree<T> interface as much as possible instead of GeneralTree<T> (e.g. replace public GeneralTree<T> Add(T item) with public ITree<T> Add(T item))
  • Make the Add(...) methods virtual so they can be overridden to return the correct ITree<T> instance.
  • Make the traversal methods virtual so they can be overridden.
  • Check if the visitor has completed before every Visit() call in the traversal methods so they can be short-circuited.

If I have time in the next few days I'll submit a pull request with some or all of these changes.

@bretthysuik
Copy link
Author

I haven't had time to look into fixing this, and it's unlikely I'll have time in the near future. You can close this bug if you want.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants