www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Give back multiple inheritance

reply sgrantham sympatico.ca writes:
I've just come across D and am impressed, although I think you (Digital Mar)
should have a comparison to Python as it would stack up against D much better
than the other languages.

I appreciate that the socialization of programming languages has driven the more
constrained approach to language structure in that the power of expression
within a language is traded off against, usefulness of expression, and the
ability of the inexperience to make a total mess (more power, more mess
potential).  However,  one of the more powerful and useful expression
capabilities of C++ is in multiple inheritance and its loss is to much of a
price.

I'll give an example in just a sec, but I want to dissuade those, whose
immediate reaction is: “Interfaces represent multiple inheritances”, from
thinking this.  If I define a class that includes multiple Interfaces, all that
I am doing is either: a) Informing the class user that the class will have a
certain behaviour (non-abstract class), which of course can be done as part of
the class definition, or informing the class deriver that they are going to have
to write a bunch of software every time they want to derive from the class.
Please don't make more work for me.  Write the software yourself.

This is not to take a way from Interfaces-- they have a purpose in stating that
a particular piece of software will have a certain behaviour, regardless of the
fact that the more object-like aspects of the software may not look much like
anything else.  They just don't represent multiple inheritance from any object
perspective.

I use the example of things organized in a tree because we have all suffered the
endless rounds of coding necessary to keep track of things in a tree collection
that is not the least bit necessary if multiple inheritance is in the picture.
I use the classic tree view of things in a PC (files, folders, devices, objects
identified by URLs, etc.)

I happened to have the following predefined (someone else’s) library of classes
for “File, “Folder”, “Device”, etc.  I also have a class named “Tree” which is
the standard implementation of a tree with the codicil that, knowing we have
multiple inheritance capabilities, we don’t have a separate class for a tree
node.  (A tree node is after all, just another tree).  So here’s how easy it is,
using multiple inheritance, to make our PC file type objects available for tree
operations.

class tFile : public File, Tree {};
class tFolder : public Folder, Tree{};
class tDevice : public Device, Tree{};

That’s it.  That’s all the code.  The only thing you might need to add is if you
need to relay constructors.  E.g.

class tFile : public File, Tree {tFile(string FileName) : File(FileName){};};

Now if the implementer of the Tree class has been smart the Tree definition has
been derived from a list definition (or a template).  For example:

class Tree : public LinkList  // pickup “Add”, “Remove” etc.
{
public:
Tree Parent;
void Add(Tree Item)  // Need to overload LinkList::Add
{
Item.Parent = this;
LinkList::Add(Item);
};

// class Tree::Enumerator

class Enumerator : private Tree, public LinkList::Enumerator 
{
// … 
// use link list enumerator but recurse through
// children
}
}

Isn’t all this so much easier?
Mar 24 2006
parent reply Johan Granberg <lijat.meREM OVEgmail.com> writes:
sgrantham sympatico.ca wrote:
 one of the more powerful and useful expression
 capabilities of C++ is in multiple inheritance and its loss is to much of a
 price.
I to want multiple inheritance but I got the feeling that walter prety much have ruled that out.
Mar 24 2006
parent reply Sean Kelly <sean f4.ca> writes:
Johan Granberg wrote:
 sgrantham sympatico.ca wrote:
 one of the more powerful and useful expression
 capabilities of C++ is in multiple inheritance and its loss is to much 
 of a
 price.
I to want multiple inheritance but I got the feeling that walter prety much have ruled that out.
For what it's worth, mixins are a capable replacement for MI in many instances. Sean
Mar 24 2006
next sibling parent reply Kyle Furlong <kylefurlong gmail.com> writes:
Sean Kelly wrote:
 Johan Granberg wrote:
 sgrantham sympatico.ca wrote:
 one of the more powerful and useful expression
 capabilities of C++ is in multiple inheritance and its loss is to 
 much of a
 price.
I to want multiple inheritance but I got the feeling that walter prety much have ruled that out.
For what it's worth, mixins are a capable replacement for MI in many instances. Sean
To bash out a quick and dirty mixin implementation: interface Tree { void Add(Tree item); } template TreeFunctionality { Tree Parent; void Add(Tree Item) { Item.Parent = this; LL.Add(Item); } // Implement LL } class tFile : File, Tree // Is the the correct syntax? { mixin TreeFunctionality; } Some other more experienced design people can help make this better I'm sure. But it gives you the idea.
Mar 24 2006
next sibling parent Sean Kelly <sean f4.ca> writes:
Kyle Furlong wrote:
 Sean Kelly wrote:
 Johan Granberg wrote:
 sgrantham sympatico.ca wrote:
 one of the more powerful and useful expression
 capabilities of C++ is in multiple inheritance and its loss is to 
 much of a
 price.
I to want multiple inheritance but I got the feeling that walter prety much have ruled that out.
For what it's worth, mixins are a capable replacement for MI in many instances.
To bash out a quick and dirty mixin implementation: interface Tree { void Add(Tree item); } template TreeFunctionality { Tree Parent; void Add(Tree Item) { Item.Parent = this; LL.Add(Item); } // Implement LL } class tFile : File, Tree // Is the the correct syntax? { mixin TreeFunctionality; } Some other more experienced design people can help make this better I'm sure. But it gives you the idea.
I have a fairly old D version of C++ IOStreams that uses mixins as a substitute for MI. Here's a link: http://www.home.f4.ca/sean/d/stream.d Sean
Mar 24 2006
prev sibling parent sgrantham sympatico.ca writes:


instance, suppose you had and abstract class called “Winged” that defined a
virtual method called “Fly” and you had two classes “Glider” and “Flapper”,
derived from “Winged”,  that each had their own implementation of method “Fly”.
Then if you created another class “FlyingMammals” that had multiple inheritance
from both “Glider” and “Flapper”, a reference to “Winged::Fly()” would be
un-resolvable at runtime because its ambiguous.  This is resolved with
"Interfaces" since they don't actually have an implementation of a particular
method so two different interfaces with the same method declaration still only
yields one implemenation.  The one in the containing class.

Having said all that I truly believe a compromise position is the order of the
day, but it requires a consolidation of what I see as a number of artifices in
languages when considered in programming abstractions.  There are several,
current, language concepts that are, to me, so intimately related that they
actually represent only one broader concept.  These are templates versus
abstract classes versus interfaces versus multiple inheritance and finally,
virtual base classes.

Instead of having all these different proto-class definitions, they can all be
collapsed into abstract classes with some extra refinement.  NOte that
Interfaces, which support multiple inheritance, are really just abstract classes
with no implmentation details.  So one need only add one additional rule to
class inheritance.  That is, "a real class can only have multiple inheritance
from abstract classes".  I.E. 

A real class may be derived from only one other real class. (The same as now.)

An abstract class may be derived from only one other real or abstract class.
(The same as now.)

A real class may be derived from one real class, but as many abstract classes as
one wants.  (This is the same as renaming "interfaces" to abstract classes and
allowing interfaces to have a default implementation.)

Abstract class derivation would be in the form of specifying inclusive lists and
exclusive lists.  Exclusive list would be bracketed.  For example:

class FlyingMammals extends Animal includes Mammal (Glider, Flapper) Arboreal
{
..
}



Then, the compiler needs to generate an "must override" error if a real class
definition attempts to inherit from multiple abstract classes that are in an
inclusive list and have any of the same public or protected member names (Or
"Required override on 'final'" if an override is blocked).  Any members, (both
properry and method), can be overridden in order to "disambiguate" the actual
implementation.  For example, if "Glider" and "Flapper" were inclusive then:

class FlyingMammals extends Animal includes Mammal Glider Flapper Arboreal
{
public void Fly()
{
if(typeof(this) != Winged || (typeof(this) == Winged && this.Tired &&
this.Airborne))
Glider::this.Fly();
else
Flapper::this.Fly();
}
}


You can then could collapes templates into this by having an abstract object
types and class abstract arguments to the class definition.  For example:

abstract class Vector( SomeType )
{
SomeType[] Elements;

..
}

Because all this is done through abstract classes, compiler implementation is
much easier in that it merely needs to build a vector table at compile time for
each of the inherited types, "union" the exlusive types and enforce overrides
for duplicate names.  
Mar 26 2006
prev sibling parent Charles <noone nowhere.com> writes:
You can also use templates for MI , see template boltins 
http://dsource.org/projects/tutorials/wiki/MultipleInheritanceWithTem
lateBoltInsExample: 


Sean Kelly wrote:
 Johan Granberg wrote:
 sgrantham sympatico.ca wrote:
 one of the more powerful and useful expression
 capabilities of C++ is in multiple inheritance and its loss is to 
 much of a
 price.
I to want multiple inheritance but I got the feeling that walter prety much have ruled that out.
For what it's worth, mixins are a capable replacement for MI in many instances. Sean
Mar 25 2006