Multiple Inheritance of Classes

Steven Schveighoffer schveiguy at yahoo.com
Wed Aug 13 09:52:24 PDT 2008


"Denis Koroskin" wrote
> 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).

I think you can do this without multiple inheritance:

class MyClass
{
   IntrusiveContainerNode!(MyClass) eventOne, eventTwo;
}

If you make IntrusiveContainerNode a struct, then there is no extra memory 
allocation necessary.

What is wrong with a solution like that?

-Steve 





More information about the Digitalmars-d mailing list