Multiple Inheritance of Classes

Denis Koroskin 2korden at gmail.com
Wed Aug 13 09:08:42 PDT 2008


On Wed, 13 Aug 2008 19:46:51 +0400, Steven Schveighoffer  
<schveiguy at yahoo.com> wrote:

> "superdan" wrote
>> Steven Schveighoffer Wrote:
>>
>>> "superdan" wrote
>>> > Lars Ivar Igesund Wrote:
>>> >
>>> >> Chris R. Miller wrote:
>>> >>
>>> >> > Understand, I'm NOT demanding ANYTHING.
>>> >> >
>>> >> > What is the current state of thought about Multiple Inheritance  
>>> for
>>> >> > classes in D?  I'd like to have that feature, since it'd make some
>>> >> > stuff
>>> >> > I want to do a bit easier.  Is it not there because it's not worth
>>> >> > the
>>> >> > effort to implement?  Because it's evil and needs to die (I don't
>>> >> > know,
>>> >> > some people could possibly be adamantly anti-MI)?
>>> >>
>>> >> This is actually the reason, not the adamantly anti-MI part, just  
>>> that
>>> >> MI
>>> >> is
>>> >> evil and that is well acknowledged almost everywhere. You will find
>>> >> good
>>> >> argumentation against it if you look, too.
>>> >
>>> > appeal to authority. appeal to ridicule. appeal to the majority. all  
>>> in
>>> > one sentence. wow. at least could you space out your fallacies a bit
>>> > more.
>>> >
>>> > the man has kindly asked a sensible question. he deserves a good
>>> > answer.
>>> > if u can't give one just don't reply. this is just ignorance.
>>>
>>> This kind of bullying bullshit does nothing to further communication,  
>>> or
>>> help anyone in the least.  You've managed to call many of the brightest
>>> developers for D idiots, usually based on useless crap like this (which
>>> has
>>> no bearing on anything).  So shut the fuck up.
>>
>> or what, u gonna kick my ass. relax. you can always block me. (but hold
>> onto that a bit more. dee's plea is just too cool.) my post did further
>> communication. it exposed the hackneyed "mi is evil" shit... i mean  
>> poop.
>> (damn.) it may have helped someone. you know what i like about walter.
>> when he doesn't know something he is open in admitting it. for that  
>> alone
>> i'd wash his feet. i didn't call the poster any name. but that  
>> particular
>> post was bull... i mean crap and i just said it. the fact that the post
>> sucked bears nothing on the fact that he's good or anything. even worse,
>> if he's good then why would he use his goodwill to get away with
>> statements like that. they only reveal ignorance and attempt at  
>> continuing
>> ignorance because it puts a stigma on anyone investigating mi. it's  
>> silly
>> we need to still talk about it. now shall we just move on to something
>> technical.
>
> I don't want to block you.  You have some good things to say (although
> colorful).  Just can it with the "what you said is stupid, so don't post
> here"  It makes tentative posters not want to post for fear of being
> ridiculed (not me BTW :) )  Some of them might have interesting things to
> say.  If you want to argue against someone's point, argue the point  
> (which
> you did later, and I found it interesting, although my personal  
> experience
> with MI (on C++) is that it sucks, and should never be used).
>
> What Lars said basically is that many people don't like MI, and you can  
> find
> proof of that (people don't like it) if you search online.  This is the
> reason Walter doesn't implement it, because he's in that camp.  I think  
> that
> is a reasonable answer to the question given.
>
> It's sort of like most the reasons Walter gives for everything new he  
> comes
> out with: "X is fundamentally broken in C++".  Substitute fundamentally
> broken with evil, substitute threading, const, etc. for X.  Can't say I
> always disagree, but his proof is certainly lacking ;)
>
>>> > interface Customer
>>> > {
>>> >    string ssn();
>>> >    string name();
>>> >    string uniqueName() { return name ~ "(ssn: " ~ ssn ~ ")"; }
>>> > }
>>> >
>>> > so uniqueName formats a specific way. a descendant can choose to  
>>> change
>>> > that or just use the default. no idea why walt chose to disallow  
>>> that.
>>> > walt?
>>>
>>> What do you pass as the 'this' pointer?  When you call a function on an
>>> interface, the compiler uses the offset of an interface to the 'this'
>>> pointer to get to the object, but in this case, there is no object, so
>>> what
>>> does the compiler do to call the ssn() and name() functions while
>>> implementing this function?
>>
>> i'm unclear about this so maybe it ain't as easy as i thought.
>> but i'm thinking the same problem goes for the global string
>> uniqueName(Customer c) { return c.name ~ "(ssn: " ~ c.ssn ~ ")"; }
>
> Not the same as the above problem, because the vtable layout for  
> Customer is
> always the same.  The name() function expects a pointer to the object,  
> and
> the implementation knows everything about the object including the  
> vtable.
> The problem with putting the implementation in the interface is that a
> member function gets a pointer to the *object* not the *interface*.  In  
> your
> new example, the 'c' parameter is a pointer to the interface, so that
> problem doesn't exist.
>
>> a pointer to this function should be put in the vtable if the object  
>> does
>> not implement it.
>
> That is fine for calling the function, but not for what to do when  
> compiling
> it.
>
>>
>>> If you pass the interface pointer as the 'this' pointer, then how do  
>>> you
>>> override it in an Object that implements the interface?  The function  
>>> in
>>> the
>>> concrete class can't be passed the interface pointer, so you can't  
>>> really
>>> override it.
>>
>> that pretty much kills what i wrote above eh. but thunking will take  
>> care
>> of it. if there's no impl in an object put a pointer to a thunk that
>> adjusts the pointer (from obj to interface) and calls the default impl
>> with the adjusted pointer. the latter is a direct call which makes it
>> fast.
>
> Hm... I think this would work actually, as I think this is a runtime  
> lookup.
> This sounds like a reasonable tradeoff, and having the final modifier if  
> you
> want it to be quicker (I think the compiler can statically do the thunk  
> if
> you know the concrete object type).  Actually, it would have to do a  
> thunk
> for a derived interface, even if you put final on it, as it can't always
> know the offset between 2 interfaces in a particular object (or can it?).
>
> Perhaps someone with better knowledge of the way interfaces work could  
> tell
> if it would be possible?
>
> -Steve
>
>

I use MI often and have positive experience with it. One good pattern that  
I use is the Intrusive container.
Suppose you have an item that you want to store in a list. Unfortunately,  
putting stuff into the single- or double-linked list leads to a memory  
allocation (unless some pool is used). Sometimes it is desirable to put  
next and prev elements into the item itself, so that no memory allocation  
is ever needed. Besides, now you can easily say whether an item is stored  
in any container. This can be implemented via inheritance:

class IntrusiveContainerNode(T)
{
     alias T ValueType;
     package T next;
     package T prev;
}

class IntrusiveContainer(TNode)
{
     alias TNode.ValueType ValueType;

     void add(ValueType value);
     void remove(ValueType value);
}

class MyClass : public Node!(MyClass)
{
    // ...
}

This imposes the restriction that an item can be stored in 1 container at  
a time. However, you can subclass twise in order to be storable in  
different containers:

typedef EventOneListener IntrusiveContainerNode;
typedef EventTwoListener IntrusiveContainerNode;

class MyClass : EventOneListener!(MyClass), EventTwoListener!(MyClass)
{
     // ...
}

MyClass instance = new MyClass();
eventOneListeners.add(instance);
eventTwoListeners.add(instance);

It is currently impossible to implement this approach using mixins (due to  
a bug I'm yet to submit).



More information about the Digitalmars-d mailing list