I wrote a class called Container which handles hierarchies (as visible to the class user) and converts them internally to a flat array. So for the outside of Container it looks like a hierarchy of Containers, each with parent and child nodes.
This functionality I want to add to certain classes. For example the Widget class, it must have that same functionality defined by Container.
I could let Widget inherit from Container. Container is now defined as a class with this(), data member, member functions, invariant and unittests. Container contains an array of Containers, so there is one fault in the design: what if Foobar also inherits Container and we add Foobar items to the Widget's container? That must be forbidden. They do share the same base class, but they are fundamentally different things with different purposes...they just seem to share some functionality.
Defining Container as an interface is not possible, since it contains data members (and doesn't solve the problem). Defining Container as mixin neither, since we have this() functionality too (or how would this work out?). Visibility attributes for functions in mixins doesn't work either. And additionally, I can't pass it the this argument of the Widget class, for that needs to be the first element of the flat array.
I thought of giving Container a template argument, telling it what container it is of:
abstract class Container(T)
{
...
T[] elements;
}
class Widget: Container!Widget
{
}
This gives an error: class container.__unittest2.Widget base class is forward referenced by Container.
How would you implement this? I could also add checks in Container that makes sure that when a child is added, it has the same type as the parent. But how do I check that?
abstract class Container
{
void add(Container child)
{
// pseudo-code
assert (is(getFirstDerivedType(this) == getFirstDerivedType(child)));
...
}
...
Container[] elements;
}
EDIT: Even if the first piece of code does not signal an error, it still doesn't really solve the problem. I cannot arbitrarily add more functionality since only one base class is allowed. The others need to be interfaces, which are fundamentally different things. Interfaces ensure there is certain functionality in the derived class, they don't add the functionality themselves.
This is supposed to be solved with (template) mixins. But mixins cannot add code to the constructor (only replace if not defined), cannot add code to invariant (invariant multiple times defined), cannot specify member function visibility or use other class/struct specific keywords...
error: class container.__unittest2.Widget base.... Care to share more? - ArlenContaineras a sub-type ofWidget? (I'm not an expert: I just read about this technique in the D book a few days ago and it seems relevant to your problem.) - Xophmeister