August 12, 2008
Chris R. Miller 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.
> 
> Looking at superdan's message, gee whiz, that didn't take long to find the implementational reasons against it.

the sinner tells the truth dood. it's not the implementation reasons. it's the reasons, period. there's no others. with one exception (smalltalk) all languages without fixed field layout do use mi. why? because aside from field layout there is no reason not to, and they already paid the price. this "it's evil" bullshit comes from c++ people tryin' it in wrong ways. just like java 1 zealots yelled all over that generics are crap. then java 5 added (assfucked) generics. guess what. javaots changed their stance. sorry about the argument by comparison fallacy :)

> Reading about next-gen compilers like LLVM it makes me wonder with all that run-time type inferencing gizmo gadgetry available at virtually no cost, will this make MI (for those who want it) more feasible to implement?  Hmm, a curious possibility to consider.  LLVM is supposed to be wicked fast, too.  My Apple friend tells me that most of OS X's GL stack is built with LLVM for speed.  There might be something to it.

i'll make another analogy. with all that research n shit, isn't perpetual motion closer to reality now? hell no. the fact that llvm is fast or smart has nothing to do with basic graph topology. the problem definition makes a solution impossible. this will be broken when someone invents some associative memory shit or some fundamental breakthrough. or when the cost of malloc and indirection becomes small enough to be affordable (solution through tradeoff inversion).

> >> I don't know.  I know
> >> I can add a lot with mixins, but I'd just like to know what the state of
> >> the feature is.
> >>
> >> The reason is I was trying to explain how cool D is to some other friends of mine, and they asked about Multiple Inheritance (of classes) and they were sort of put off by it's lack of it.  Then again, he was an Objective-C programmer...  ;-)
> > 
> > In the languages where MI is possible, it usually also is possible to not shoot your own foot with some care, in which case it can appear as a powerful feature. But almost everywhere it just is a very bad idea, and you will find it is banned in many projects for languages allowing it (like C++).
> 
> Look long enough and you can find anything.  ;-)
> 
> I see your point though.

i don't. he has none. he keeps on saying it's a "very bad idea". he could sing it for all i care. how does that make it more pointful.

> >> So please don't take offense, since none is meant, I just wanted to know what I could hope for in the future.
> > 
> > You should hope you can redesign your application to not need MI ;)
> 
> Yeah, it's trivial to work around it (I did come from Java!) but some bits and pieces seem like it would be better if they could inherit behavior and data, not just a contract.  It could be done through a mixin, but that defeats the polymorphism I want present in the design. And a Mixin and an interface just seems clunky.  What if I do the mixin but forget the interface, or vice-versa?  Yuk!  Though it would give me the option of re-implementing it differently if necessary...  a curious silver lining.

the silver lining is in introspection. with it you can define classes that define forwarding functions to other classes. that is almost mi, good enough for many uses.
August 12, 2008
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.

> 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.

I took it as a tongue-in-cheek question, and so was my answer. If Chris took offense, I am sorry. I am however happy that you provided a good technical response for once.

-- 
Lars Ivar Igesund
blog at http://larsivi.net
DSource, #d.tango & #D: larsivi
Dancing the Tango
August 12, 2008
Manfred_Nowak Wrote:

> superdan wrote:
> 
> > with mi it is impossible to lay out objects in a fixed layout. unless you do it [...]
> 
> I do not understand this. Do you mean, that it is impossible or do you mean one can do a fixed layout _with_ mi?

man there's a ton to explain and then some more. i got work n shit to do but let me try. stay with me ok? take a pen and paper and draw this shit. simple hierarchy:

class a { ubyte x[100]; }
class b : a { ubyte y[200]; }
class c : a { ubyte z[500]; }

let's lay a and b out. you could lay both out with the base first or last. you must be consistent. can't hand-pick your guesses. say you decide base first:

b : x y
c : x z

so far so good. these decisions were made. can't be rethought later. because it's fixed layout, remember. put'em in ur pocket. now comes this motherfucker:

class bc : b, c {}

now you want b and c to be subobjects of bc with the same layout of b and c alone. so for bc there's only two cut and dried choices. either b then c or c then b. let's choose the first and unroll that shit:

bc : [ x y x z ]

but you don't want that because there are two xs where there should be one. see now how topological layout of a dag on a 1-dimensional line (linear memory) can't cut the shit.

but say you hand pick this example and make it work:

b : [ y z ]
c : [ z x ]
bc : [ y z x ]

youza that works. but then if you do this:

class d : b, bc {}
class e : d, bc {}

that grandmotherfucks the entire situation. there's no way to lay that shit out. unless you know the hierarchy in advance. which is unreasonable. and you also have to allow for holes in objects. that also sucks ass.

> Then: given that "D is a systems programming language", how would one implement an efficient system, for which a requirement for mi exists, in D?

good question. i have two thoughts.

one is with stacked templates. that allows you not mi but stacked si.

class a(t = Object) : t {}
class b(t = Object) : t {}
class ab : b!(a!()) {}

that way you draw your own layout on a line. it sucks that d doesn't allow a to mean a!(). the latter looks like shit. (i mean shit in a bad way.) but that's not true mi because different as and bs come templated with different arguments. they mean nothing to one another. that's only good for inheritance of implementation shit.

second thought. i think introspection may be the shit. (here i mean shit in a good way.) use classic layout for one base. then use indirection thru refs for the layout of the rest. introspection plops the forwarding functions. opImplicitCast adds seasoning for taste. this looks like some std.typecons shit.
August 12, 2008
superdan Wrote:

> Manfred_Nowak Wrote:
> 
> > superdan wrote:
> > 
> > > with mi it is impossible to lay out objects in a fixed layout. unless you do it [...]
> > 
> > I do not understand this. Do you mean, that it is impossible or do you mean one can do a fixed layout _with_ mi?
> 
> man there's a ton to explain and then some more. i got work n shit to do but let me try. stay with me ok? take a pen and paper and draw this shit. simple hierarchy:
> 
> class a { ubyte x[100]; }
> class b : a { ubyte y[200]; }
> class c : a { ubyte z[500]; }
> 
> let's lay a and b out. you could lay both out with the base first or last. you must be consistent. can't hand-pick your guesses. say you decide base first:
> 
> b : x y
> c : x z
> 
> so far so good. these decisions were made. can't be rethought later. because it's fixed layout, remember. put'em in ur pocket. now comes this motherfucker:
> 
> class bc : b, c {}
> 
> now you want b and c to be subobjects of bc with the same layout of b and c alone. so for bc there's only two cut and dried choices. either b then c or c then b. let's choose the first and unroll that shit:
> 
> bc : [ x y x z ]
> 
> but you don't want that because there are two xs where there should be one. see now how topological layout of a dag on a 1-dimensional line (linear memory) can't cut the shit.
> 
> but say you hand pick this example and make it work:
> 
> b : [ y z ]
> c : [ z x ]
> bc : [ y z x ]
> 
> youza that works. but then if you do this:
> 
> class d : b, bc {}
> class e : d, bc {}
> 
> that grandmotherfucks the entire situation. there's no way to lay that shit out. unless you know the hierarchy in advance. which is unreasonable. and you also have to allow for holes in objects. that also sucks ass.
> 
> > Then: given that "D is a systems programming language", how would one implement an efficient system, for which a requirement for mi exists, in D?
> 
> good question. i have two thoughts.
> 
> one is with stacked templates. that allows you not mi but stacked si.
> 
> class a(t = Object) : t {}
> class b(t = Object) : t {}
> class ab : b!(a!()) {}
> 
> that way you draw your own layout on a line. it sucks that d doesn't allow a to mean a!(). the latter looks like shit. (i mean shit in a bad way.) but that's not true mi because different as and bs come templated with different arguments. they mean nothing to one another. that's only good for inheritance of implementation shit.
> 
> second thought. i think introspection may be the shit. (here i mean shit in a good way.) use classic layout for one base. then use indirection thru refs for the layout of the rest. introspection plops the forwarding functions. opImplicitCast adds seasoning for taste. this looks like some std.typecons shit.

So why not just dissalow diamond-pattern MI?
August 12, 2008
"Robert Fraser" <fraserofthenight@gmail.com> wrote in message news:g7surd$21u0$1@digitalmars.com...

> So why not just dissalow diamond-pattern MI?

A singly-rooted object hierarchy like D has precludes that from being possible.  Everything will ultimately go back to Object.


August 12, 2008
superdan wrote:
> Manfred_Nowak Wrote:
> 
>> superdan wrote:
>> 
>>> with mi it is impossible to lay out objects in a fixed layout. unless you do it [...]
>> I do not understand this. Do you mean, that it is impossible or do you mean one can do a fixed layout _with_ mi?
> 
> man there's a ton to explain and then some more. i got work n shit to do but let me try. stay with me ok? take a pen and paper and draw this shit. simple hierarchy:
> 
> class a { ubyte x[100]; } class b : a { ubyte y[200]; } class c : a { ubyte z[500]; }
> 
> let's lay a and b out. you could lay both out with the base first or last. you must be consistent. can't hand-pick your guesses. say you decide base first:
> 
> b : x y c : x z
> 
> so far so good. these decisions were made. can't be rethought later. because it's fixed layout, remember. put'em in ur pocket. now comes this motherfucker:
> 
> class bc : b, c {}
> 
> now you want b and c to be subobjects of bc with the same layout of b and c alone. so for bc there's only two cut and dried choices. either b then c or c then b. let's choose the first and unroll that shit:
> 
> bc : [ x y x z ]
> 
> but you don't want that because there are two xs where there should be one. see now how topological layout of a dag on a 1-dimensional line (linear memory) can't cut the shit.
> 
> but say you hand pick this example and make it work:
> 
> b : [ y z ] c : [ z x ] bc : [ y z x ]
> 
> youza that works. but then if you do this:
> 
> class d : b, bc {} class e : d, bc {}
> 
> that grandmotherfucks the entire situation. there's no way to lay that shit out. unless you know the hierarchy in advance. which is unreasonable. and you also have to allow for holes in objects. that also sucks ass.
> 
>> Then: given that "D is a systems programming language", how would one implement an efficient system, for which a requirement for mi exists, in D?
> 
> good question. i have two thoughts.
> 
> one is with stacked templates. that allows you not mi but stacked si.
> 
> 
> class a(t = Object) : t {} class b(t = Object) : t {} class ab :
> b!(a!()) {}
> 
> that way you draw your own layout on a line. it sucks that d doesn't allow a to mean a!(). the latter looks like shit. (i mean shit in a bad way.) but that's not true mi because different as and bs come templated with different arguments. they mean nothing to one another. that's only good for inheritance of implementation shit.
> 
> second thought. i think introspection may be the shit. (here i mean shit in a good way.) use classic layout for one base. then use indirection thru refs for the layout of the rest. introspection plops the forwarding functions. opImplicitCast adds seasoning for taste. this looks like some std.typecons shit.

About your first thought:
can you compare your (C++ templates) solution with D mixins?
why would I choose that approach instead of template mixins if it's only
good for inheritance of implementation?
I think (and I'm sure you'll correct me if I'm wrong) that mixins remove
the need for that pattern entirely.

In another post of yours you referred to adding function bodies to interfaces. Do you have any ideas on how to implement this efficiently?

last question: can you explain what do you mean by non fixed layout languages that have MI?
August 12, 2008
Reply to superdan,

> BCS Wrote:
> 
>>> appeal to ridicule. appeal to the majority.
>>> 
>> Both reasonable if enough people are doing the ridicule (95%
>> majority?), again with the disclaimer for the occasional
>> expert/academic that most of us (walter excluded) don't have anywhere
>> near the time to become.
>> 
> i don't find either particularly reasonable.
> http://en.wikipedia.org/wiki/Appeal_to_ridicule
> 

OK I got that backwards: appeal to ridicule != lots of people ridicule it

> http://en.wikipedia.org/wiki/Argumentum_ad_populum. if you don't have
> the time to become an expert just let walter or some expert answer.
> that post reveals zero knowledge on the subject. merely a perpetuation
> of the "it's evil" heard from someone else and ingested noncritically.
> after "don't do it!!! it's evil!!!" all i can expect next is "keep the
> faith!!!" fuck man.
> 

I'm not saying either is a good proof or even a strong argument, but if you don't have time to form your own opinion (and like it or not most of the time you don't) both work reasonably well untill you do have time. 

And in this cases I think it is more of an opinion summery that a proof or argument.

>>> 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.
>>> 
>> I think that was a good answer to the question "Why doesn't D have
>> MI?"
>> 
> "it's evil" is a good answer? cut the shit man. why is it evil again?
> your critical reasoning filter ever questioned that assertion?
> 
>>> below's an attempt at an answer.
>>> 
>> The below is a reasonable answer to "Justify D's lack of MI." or
>> "What is the rational for D's not having MI?" Those are different
>> questions that what Lars was going for.
>> 
> pardon me if i'm dense but i have a hard time distinguishing between
> the two. and pardon me if i continue to think "it's evil" is mere
> oxshit.
> 

the one answer is like saying "don't drive over 35 MPH on that street because it's illegal" the other answer is like saying "it is illegal to drive over 35 MPH because there are small children playing there"

Another way of looking at it would be that the first is like saying "I did B after reading the paper 'A is a bad Idea' " and the second is the paper it's self. 

>>> first i repeat what is already known. d does do multiple inheritance
>>> thru interfaces.
>>> 
>> Is interfaces MI? That is debatable because, as you point out, there
>> is a huge difference between it and MI->data & MI->implementation.
>> 
> it's not debatable. interfaces are inheritance. they satisfy the
> definition. (substitution principle.) if you implement multiple
> interfaces you do mi. case closed. to summarize: d does mi of
> interface but not mi of data and not mi of implementation. they are
> different flavors of shit but that does not make interfaces mi
> debatable.
> 

OK fine, pick a word (I'll use ___) that applyes to the stuff D dosn't do and not to the stuff it does. The OP wants to talk about why D dosn't have ___. Talking about if ___ is MI is realy boring so lets not.

>> Yeah, I've wanted that, OTOH it might get tricky to implement because
>> of the mechanics of interfaces.
>> 
[...]
>> 
> nothing that walt can't do.
>

I'll have to go with "He has better thigns to do" on that one.


August 12, 2008
superdan wrote:
> better put doesn't do multiple inheritance of data. why? simple. d is a fixed layout language. means that the offset of any data member within the object is known during compilation. with mi it is impossible to lay out objects in a fixed layout. unless you do it the nonsensical way c++ does. at least you can't lay out with 1-dimensional memory. (i've done vlsi design and sure as shit 2-dim helps a lot. but a lot more could be done with 3-dim. i remember only adding two layers was a huge deal.) with mi from n classes you'd need n-dimensional ram. that's why only simple inheritance is possible with 1-dimensional ram. if u want fixed layout that is. (now that i got into it there was a guy who did 2-class inheritance by storing stuff at positive and negative offsets, thus adding a 2nd dimension.) mi of interfaces is a good thing and putting an int in an interface does not make it evil. just makes it impossible to lay out.

Which begs the question of why D is a fixed layout language. My impression is that, if MI was a high enough priority, the data layout issues could be easily solved (maybe by having the compiler automatically generate the necessary interfaces and mixins, and using a separate data layout for each inheritance permutation).

My understanding of *why* that route wasn't taken is that, from a design perspective, MI creates interface ambiguities that the programmer would usually rather not deal with. For example:

class A { public int xyz() { ... } }

class B { public int xyz() { ... } }

class C : A, B { ... }

C c = new C();
c.xyz(); // ambiguous

Sure, you could have the programmer explicitly disambiguate which xyz method to call, with something like this:

((A) c).xyz();

But is it really worth it, especially given the compiler gymnastics required to solve the data layout obstacles?

My impression has always been that the design consequences of MI in D made it undesirable (that's what people mean when they say that MI is "evil" or "ugly" or any of those other subjective, hyperbolic terms). The implementation hurdles could be overcome if MI was desirable, so it's not an insurmountable technical challenge as superdan's message implies.

I could be wrong in my recollection of the history of D, but that's how I remember the discussions from three or four years ago, when MI was a more commonly discussed topic. Mixins (code mixins, not string mixins, which didn't exist yet) were introduced specifically as a mechanism to avoid MI, avoiding code duplication without resorting to the ambiguities of MI.

--benji
August 12, 2008
Jarrett Billingsley Wrote:

> "Robert Fraser" <fraserofthenight@gmail.com> wrote in message news:g7surd$21u0$1@digitalmars.com...
> 
> > So why not just dissalow diamond-pattern MI?
> 
> A singly-rooted object hierarchy like D has precludes that from being possible.  Everything will ultimately go back to Object.

would work if Object had absolutely no state. but it has the vptr and the synchronization shit. that fucks the plan right there.
August 12, 2008
Yigal Chripun Wrote:

> About your first thought:
> can you compare your (C++ templates) solution with D mixins?
> why would I choose that approach instead of template mixins if it's only
> good for inheritance of implementation?
> I think (and I'm sure you'll correct me if I'm wrong) that mixins remove
> the need for that pattern entirely.

how would the mixin solution look like?

> In another post of yours you referred to adding function bodies to interfaces. Do you have any ideas on how to implement this efficiently?

each interface defines a vtable layout. it does not define what the table contains. a class implementing an interface will fill that vtable with its own functions. if a class forgets to fill all slots there's an error because there's nothing to fill that slot with. with me so far?

now if an interface defines function bodies, that simply means there are defaults for some of those entries. that's all. if the derived class doesn't fill them they are filled and the compiler calls it a day. (walt please confirm.)

now i know everybody and their fave hooker has a pet feature to add to d, but i'd really like that shit in d2. it would raise interface powers to a whole new level. why? because you can define an interface that defines high-level functions that callers can use yet requires the implementers to implement the low-level primitives. i think i saw this shit in herb sutter. he calls it non-virtual idiom or some'n'.

that shit is essential for contracts, too. contracts in d are fucked up. it's a cryin' shame. contracts should be on interfaces so they enforce shit on their implementors. as they should. right now only implementors can enforce shit on their own ass. how's that helpful i don't see.

interface Stack!(T)
{
    bool empty();
    T push() out { enforce(!empty); }
    T pop() in { enforce(!empty); }
    T top() in { enforce(!empty); }
}

now the stack writer not only wishes the implementer does some sensible shit. he also makes sure shit is respected. and if you think of it for a minute you'll see how this kind of requires implementation of functions in interfaces.

> last question: can you explain what do you mean by non fixed layout languages that have MI?

clos, python, perl, curl. even javascript. they have non-fixed layout. with hashes mapping names to values and shit. they would have to go out of their way to disallow mi. so they just allow it because "it's not evil". it just costs.