September 02, 2001
"Axel Kittenberger" <axel@dtone.org> wrote in message news:9mst9n$2o41$1@digitaldaemon.com...
> > Yu Qian Zhou wrote in message ...
> >>BTW, Walter, have you decided to introduce any better approach into D other than Java's single inheritance + interface + "Copy&Paste" ?
> >
> >
> > No, I haven't. I understand that not having MI will result in some code duplication. I don't think, however, it is a cost that exceeds the
greater
> > understandability of non-MI code.
>
> I have to agree with Yu Qian, I've programmed some GUI's and java and sometimes you've objects which have implement several interfaces, but
often
> only a single function of each. A good example are the 'Listeners' java has. A listener would be an event slot in qt language. You get all the GUI actions into there. Example were something like KeyboardListener, MouseListener, etc. Suprisingly the java API always provides each listener twice, once as an interface, and once as a normal class you can inherit.
If
> the situation allows it you can inherit the Listener class and just overload the functions you want, but in some situations you alread inherit from something else. Then you've to implement the interface and write code for -every- function it provides. This is the code duplication how I think Yu Qian tried to express.

Java does not always provide classes that instantiate interfaces, it's usually only done for interfaces that have a large number of methods and for which it is valid to leave all the methods empty (so you only specifiy the ones you want and leave everything else as empty).  I think Walter's point about the readibility trade off is a good one - the cost you mention is slight (and providing a do-nothing implementation of large interfaces is a one-off cost paid by writers of library code - big deal! :-) )

> In my eyes somebody thought simple single inheritence was enough. Sounds like a good idea. But in pratice they soon discovered that there are cases it does not suffice, like in many cases one often seen example in java is 'Application' and 'Runable'. Okay you've to inherit for an Application to be start able. If you want to run another thread you've to implement the 'Runable' interface, because you can't overload also the 'Thread' class since you are already an application. In this dilemma the interfaces were introduced, a suitable workaround. But exactly in this example writing threaded code by inheriting 'Thread' is far more convient than
implementing
> the 'Runable' interface which requires you to write more code, and to create an additional thread object as 'branch'.

Interfaces were not introduced as a workaround to not having MI in Java, they were implemented from the start as a concious design choice.

> I think single inheritence was an expiriment, worth taking altough. But looking at the results my impression is it failed.

Well, there are a lot of people who would say that Java provides proof that the need for MI is slim.  One of the things that I hear most from people who like Java is that it produces much cleaner, more maintainable code that C++.

>Why can't I just inherit
> both from 'Application' and from 'Thread' at the same time? I don't think MI is any bad if you implement it stronger typed than C++ did. A function is eitherway absolute unique identifyable or a compile error will be raised. The worst case that can happen is that the user has to specify
from
> which parent he wants to call the function Foo() if both should have them.

Eiffel has a resolution system that allows the programmer to disambiguate parent symbols in this way.  From all accounts, it seems to work quite well.

> Another aspect which make C++ inheritance complicated is public, protected and private inheritance. Something I never understood what the real benefits of it are. In the sense IS-A and HAS-A, I can hide what I have, but I should not be able to hide what I am.
>
> Diamond inheritance? If it makes problems, just leave it away. You're
still
> far more powerfull than single inheritence would provide.
>
> - Axel


September 02, 2001
> Java does not always provide classes that instantiate interfaces, it's usually only done for interfaces that have a large number of methods and for which it is valid to leave all the methods empty (so you only specifiy the ones you want and leave everything else as empty).

At least for almost all the 'Listener' interfaces there are empty classes. The parallels are not often seeable at first sight like the other example I brought already the 'Thread' class vs. the 'Runable' as signle inheritance workaround interface.

> Interfaces were not introduced as a workaround to not having MI in Java, they were implemented from the start as a concious design choice.

What you've seen as release 1.0 of java has also an evolution behind it.

> Well, there are a lot of people who would say that Java provides proof that the need for MI is slim.  One of the things that I hear most from people who like Java is that it produces much cleaner, more maintainable code that C++.

That java produces far mor maintainable code than C++ is no secret, but this is an effeact that results from the summeration of all differences. MI must not be necessarly one of these. I think the miss of general pointers, the strong exceptions, the garbadge collector memory managment and all that proive easier maintainable code, one can't cleanly say this is because of having SI over MI.

- Axel
September 02, 2001
Axel Kittenberger wrote:
> Another aspect which make C++ inheritance complicated is public, protected and private inheritance. Something I never understood what the real benefits of it are. In the sense IS-A and HAS-A, I can hide what I have, but I should not be able to hide what I am.

	I think the is one of the interesting this C++ got convoluted.  I like
the way LX handled this.  Think of it this way, in C you have:

	Interface: you get the ISA relationship but no data or implementation
		   (Yes, this isn't C++ but you get it with a virtual base class.
		   Interfaces aren't bad, just not the answer to everything.)

	Public Inheritance: You get ISA, implementation and data

	Private Inheritance: You don't get ISA, but you get implementation and
data
			     Only your closest 'friend' know where you got it

	Protected Inheritance: You don't get ISA, but you get implementation
and data
			       Only your children know the family secret.

In LX there are to basic form of inheritance, you have inherit the
interface from an object giving you the ISA relationship.  You can then
separately inherit the implementation.  You are still free to override
if I recall correctly.  This doesn't support the cases were you only
have the ISA relation for a small subset of code.  I'm am curious if and
how that would be missed.
	In the end I think LX makes it clearer by separating the two forms of
inheritance and let you do one the other or both for a class.  It
requires two clauses to get the equivalent of C++'s public inheritance,
but I still think it makes it easier to understand what you are getting.

> Diamond inheritance? If it makes problems, just leave it away. You're still far more powerfull than single inheritence would provide.

	In D you will always have Diamond inheritance because of the Object
base class.  Living without Diamond inheritance in an MI world is
probably harder than living without MI in an SI world.  If you have MI,
Diamond just seem to happen and the Object base is a great example why.
I imagine frameworks have that problem a lot too.  Disabling diamonds in
MI would probably turn into an example of how idealism crippled a
feature.
	This simple fact is that Walter is right.  C++ buggered up MI, and I
think the only way to get it into D is if we can find a set of semantics
that

	- has the useful MI feature that you can't get with SI and interfaces
	- that doesn't have the ambiguities of C++ style inheritance
	- won't turn the compiler into an AI experiment
	- that does not require Ph.D.. level knowledge to fully grasp.
	  (I challenge anyone to explain C++ inheritance fully and clearly
	  in one page, 8 pt. font, 1 inch margins.)

I've heard people take about other languages getting it better, but I am not familiar enough with any of the languages to argue there merits or flaws.  Any ideas?  Remember that operator overloading and generic programming are still on the table, so be careful not to rule those out.

Dan
September 02, 2001
> I think the is one of the interesting this C++ got convoluted.  I like the way LX handled this.  Think of it this way, in C you have:

Well to pendantic in C (without ++) you've no objects at all :o)


> Interfaces aren't bad, just not the answer to everything.)

Nothing is the answer to everything, and I dislike languages that present themselfs as the ultimate answer.


> Private Inheritance: You don't get ISA, but you get implementation and
> data
> Only your closest 'friend' know where you got it

Hmmm, but what is here now the real difference to HASA?

> In LX there are to basic form of inheritance, you have inherit the interface from an object giving you the ISA relationship.  You can then separately inherit the implementation.  You are still free to override if I recall correctly.  This doesn't support the cases were you only have the ISA relation for a small subset of code.  I'm am curious if and how that would be missed.

That sounds to be produce quite 'expensive' runtime code (assembler). I
would stick with the user having to write clear interface or the same in MI
abstract classes. Overrideable functions requires 'invisible' function
pointers. (the virtual keyword in C++)

> In D you will always have Diamond inheritance because of the Object base class.

Well the 'Object' class has on most systems a special status, (most trivial is the implicit inheritance,)

> Living without Diamond inheritance in an MI world is probably harder than living without MI in an SI world.

Thats pretty confusing. There are no sperated MI and SI worlds, MI without diamonds is still plain and simply more powerfull than SI. Remember in MI you can still create interface through pure abstract classes.

> If you have MI,
> Diamond just seem to happen and the Object base is a great example why.
> I imagine frameworks have that problem a lot too.  Disabling diamonds in
> MI would probably turn into an example of how idealism crippled a
> feature.

That very same crippled statement you can say about SI vs. MI.


> This simple fact is that Walter is right.  C++ buggered up MI, and I think the only way to get it into D is if we can find a set of semantics that
> 
> - has the useful MI feature that you can't get with SI and interfaces
> - that doesn't have the ambiguities of C++ style inheritance
> - won't turn the compiler into an AI experiment
> - that does not require Ph.D.. level knowledge to fully grasp.
> (I challenge anyone to explain C++ inheritance fully and clearly
> in one page, 8 pt. font, 1 inch margins.)

That goes to all language features :o)

> I've heard people take about other languages getting it better, but I am not familiar enough with any of the languages to argue there merits or flaws.  Any ideas?  Remember that operator overloading and generic programming are still on the table, so be careful not to rule those out.

Well I'm not trying to move D in a special direction, as many seem here to do :/ So far I found this newsgroup an invaluable resource to get the 'Zeitgeist' people want today from a language. I've also efforts going writing a new language, however in my case it's a pure hobby.

- Axel

-- 
[D) http://www.dtone.org

September 02, 2001
I agree with Walter entirely about the enhanced readability and maintainability of Interfaced code vs M.I.  I also agree with you that in Java, having to implement entire interfaces is a pain in the butt. Honestly, how many times do you extend a Frame, make it be it's own WindowListener, stub out all the methods but windowClosing() and have that be system exit?

All the other stubs in there can be a PAIN.

So, I offer up a solution.  I've been lax in keeping up with the newsgroup lately, so forgive me if this has been suggested, but how about this - Provide a compiler switch that, if a class implements an interface but does not actually implement each of the required functions of the interface, causes the compiler to automatically insert empty stubs for the non-implemented functions.

The issue of functions that actually return values comes up.  Again pointing to Java experience, I find that interfaces with purly/mostly void functions (ie, EventListeners), I stub out all but one or two.  Interfaces with functions that actually return values I tend to implement entirely, though it depends on the application, of course.

So this compiler switch could stub out void methods, obviously, and perhaps it could have value returning methods simply return the default value - ie, Object returns could be "null", integer returns could be 0, booleans be false.  (true could be up for debate, or be another compiler switch)

The void obviously isn't a problem, and once again I point out that interface functions that actually return values tend to get meaninful implementations anyway.  The coder would either implement them knowing that it's the right thing to do, or if he truly doesn't care and he knows the language well enough to use this compiler switch, he understands the consequences of the "auto-stub" function making his code return default values.

Anyways, just a thought.  I'd love to hear everyone's opinions.

-Brady



"Axel Kittenberger" <axel@dtone.org> wrote in message news:9mst9n$2o41$1@digitaldaemon.com...
> > Yu Qian Zhou wrote in message ...
> >>BTW, Walter, have you decided to introduce any better approach into D other than Java's single inheritance + interface + "Copy&Paste" ?
> >
> >
> > No, I haven't. I understand that not having MI will result in some code duplication. I don't think, however, it is a cost that exceeds the
greater
> > understandability of non-MI code.
>
> I have to agree with Yu Qian, I've programmed some GUI's and java and sometimes you've objects which have implement several interfaces, but
often
> only a single function of each. A good example are the 'Listeners' java has. A listener would be an event slot in qt language. You get all the GUI actions into there. Example were something like KeyboardListener, MouseListener, etc. Suprisingly the java API always provides each listener twice, once as an interface, and once as a normal class you can inherit.
If
> the situation allows it you can inherit the Listener class and just overload the functions you want, but in some situations you alread inherit from something else. Then you've to implement the interface and write code for -every- function it provides. This is the code duplication how I think Yu Qian tried to express.
>
> In my eyes somebody thought simple single inheritence was enough. Sounds like a good idea. But in pratice they soon discovered that there are cases it does not suffice, like in many cases one often seen example in java is 'Application' and 'Runable'. Okay you've to inherit for an Application to be start able. If you want to run another thread you've to implement the 'Runable' interface, because you can't overload also the 'Thread' class since you are already an application. In this dilemma the interfaces were introduced, a suitable workaround. But exactly in this example writing threaded code by inheriting 'Thread' is far more convient than
implementing
> the 'Runable' interface which requires you to write more code, and to create an additional thread object as 'branch'.
>
> I think single inheritence was an expiriment, worth taking altough. But looking at the results my impression is it failed. Why can't I just
inherit
> both from 'Application' and from 'Thread' at the same time? I don't think MI is any bad if you implement it stronger typed than C++ did. A function is eitherway absolute unique identifyable or a compile error will be raised. The worst case that can happen is that the user has to specify
from
> which parent he wants to call the function Foo() if both should have them.
>
> Another aspect which make C++ inheritance complicated is public, protected and private inheritance. Something I never understood what the real benefits of it are. In the sense IS-A and HAS-A, I can hide what I have, but I should not be able to hide what I am.
>
> Diamond inheritance? If it makes problems, just leave it away. You're
still
> far more powerfull than single inheritence would provide.
>
> - Axel


September 02, 2001
Axel Kittenberger wrote:

>> Yu Qian Zhou wrote in message ...
>>>BTW, Walter, have you decided to introduce any better approach into D other than Java's single inheritance + interface + "Copy&Paste" ?
>> 
>> 
>> No, I haven't. I understand that not having MI will result in some code duplication. I don't think, however, it is a cost that exceeds the greater understandability of non-MI code.
> 
> I have to agree with Yu Qian, I've programmed some GUI's and java and sometimes you've objects which have implement several interfaces, but often only a single function of each. A good example are the 'Listeners' java has. A listener would be an
>...
> 
> Diamond inheritance? If it makes problems, just leave it away. You're still far more powerfull than single inheritence would provide.
> 
> - Axel
> 
A part of what is involved is limited developer time.  But if Eiffel style multiple-inheritence is impractical, then I would plump for the kind of delegation that Jamie used (Jamie was/is a preprocessor for Java).  You could also look at Kiev for some solutions.  But Kiev is a complier for the JVM, where Jamie is a preprocessor for Java.

N.B.:  This use is delegation isn't exactly the same as what MS was proposing for J++.  I haven't even looked at C#, so maybe they've changed their terminology.  (It does mean forwarding calls from one class to another without writing a lot of patchwork, but as Jamie implements it, some calls can be forwarded to one class, and others to another.)

At all events, if space is left open for it, delegation can be added during a second iteration of the language.  It doesn't need to be present from the start.
September 03, 2001
Axel Kittenberger wrote:
> 
> > I think the is one of the interesting this C++ got convoluted.  I like the way LX handled this.  Think of it this way, in C you have:
> 
> Well to pendantic in C (without ++) you've no objects at all :o)

	Well, in my little world things are different ....
	:-)

> > Private Inheritance: You don't get ISA, but you get implementation and
> > data
> > Only your closest 'friend' know where you got it
> 
> Hmmm, but what is here now the real difference to HASA?

	It says the derived class has all the same HASA relationships as the
parent, with out manually cutting and pasting code and forwarding method
calls.  On the other hand, a pointer to the parent class cannot be
assigned a reference to the child class.  It is for code reuse, but not
polymorphism.

> > In LX there are to basic form of inheritance, you have inherit the interface from an object giving you the ISA relationship.  You can then separately inherit the implementation.  You are still free to override if I recall correctly.  This doesn't support the cases were you only have the ISA relation for a small subset of code.  I'm am curious if and how that would be missed.
> 
> That sounds to be produce quite 'expensive' runtime code (assembler). I would stick with the user having to write clear interface or the same in MI abstract classes. Overrideable functions requires 'invisible' function pointers. (the virtual keyword in C++)

	Well, I can't say for sure myself.  I don't think it would be expensive
though.  The implementation inheritance is just a matter the the
compiler doing a cut and paste on the programmer's behalf.  The
interface inheritance would be the same as inheriting from a pure
virtual base class, even if it isn't pure virtual.  LX was pretty
flexible too about these things.  It looked like LX would have
performance problems because of some of it's features, but this isn't
one I expected to cause problems.

> > In D you will always have Diamond inheritance because of the Object base class.
> 
> Well the 'Object' class has on most systems a special status, (most trivial is the implicit inheritance,)
>
> > Living without Diamond inheritance in an MI world is probably harder than living without MI in an SI world.
> 
> Thats pretty confusing. There are no sperated MI and SI worlds, MI without diamonds is still plain and simply more powerfull than SI. Remember in MI you can still create interface through pure abstract classes.

	It wasn't a very clear statement, but basically, the diamond shaped
inheritance graph is pretty common in when using MI to build
frameworks.  This obviously isn't a problem in SI, because you don't
have the necessary features to get you to that inheritance problem.  On
the other hand, divide by zero wouldn't be a problem either if we would
just get rid of that nasty division operator.

> > If you have MI,
> > Diamond just seem to happen and the Object base is a great example why.
> > I imagine frameworks have that problem a lot too.  Disabling diamonds in
> > MI would probably turn into an example of how idealism crippled a
> > feature.
> 
> That very same crippled statement you can say about SI vs. MI.

	You won't get any argument for me here.  It's just frameworks often
like to have common base classes and combining two type derived from the
common root would be pretty common in C++ I would think.  I'd just hate
to add a crippled MI implementation and have someone say "There! Now
stop complaining!"  I also don't want another bad implementation of MI
that would give opponents of MI more ammunition to claim the entire
paradigm is flawed.

> > This simple fact is that Walter is right.  C++ buggered up MI, and I think the only way to get it into D is if we can find a set of semantics that
> >
> > - has the useful MI feature that you can't get with SI and interfaces
> > - that doesn't have the ambiguities of C++ style inheritance
> > - won't turn the compiler into an AI experiment
> > - that does not require Ph.D.. level knowledge to fully grasp.
> > (I challenge anyone to explain C++ inheritance fully and clearly
> > in one page, 8 pt. font, 1 inch margins.)
> 
> That goes to all language features :o)

	Now hey, C++ didn't bugger everything.  Seriously though, C++ got so
complex because of how it tried to resolve ambiguities.  This is true of
it's MI and templates.  Java inheritance would be pretty easy to explain
by comparison.  They simply recognized the C++ MI implementation had
problems, so they lopped off a leg to fix a problem in the foot.
	Now let me get back to those divide by zero problems.  You know a naval
ship was dead in the water as a result of a divide by zero.  The
division operator is just too dangerous.  Besides, we can bit shift.
It's the same as dividing by powers of two without all the dangers.

> > I've heard people take about other languages getting it better, but I am not familiar enough with any of the languages to argue there merits or flaws.  Any ideas?  Remember that operator overloading and generic programming are still on the table, so be careful not to rule those out.
> 
> Well I'm not trying to move D in a special direction, as many seem here to do :/ So far I found this newsgroup an invaluable resource to get the 'Zeitgeist' people want today from a language. I've also efforts going writing a new language, however in my case it's a pure hobby.

	I want someone to take this in a special direction.  One as functional
as C++ without the convoluted rules.  If other languages did it better,
I'd like to know how.  I'm floundering here.

Dan
September 03, 2001
"Axel Kittenberger" <axel@dtone.org> wrote
>
> I think single inheritence was an expiriment, worth taking altough. But looking at the results my impression is it failed. Why can't I just
inherit
> both from 'Application' and from 'Thread' at the same time? I don't think MI is any bad if you implement it stronger typed than C++ did. A function is eitherway absolute unique identifyable or a compile error will be raised. The worst case that can happen is that the user has to specify
from
> which parent he wants to call the function Foo() if both should have them.
>
> Another aspect which make C++ inheritance complicated is public, protected and private inheritance. Something I never understood what the real benefits of it are. In the sense IS-A and HAS-A, I can hide what I have, but I should not be able to hide what I am.
>
> Diamond inheritance? If it makes problems, just leave it away. You're
still
> far more powerfull than single inheritence would provide.
>

I'm with you Axel.  The important question it seems to me is: - what is so confusing about MI?

Programmers spend a _lot_ of our time trying to reverse engineer other
people's code.  MI makes this harder because it's so hard to figure out what
a function call does.
You see
DoTheThing();
and you have to ask, is this a global function? Is it a method?  Is it
defined here or in a base?  Is it overridden? Overloaded?  Does it have
defaulted arguments? Is it inherited from two different base classes?  Is it
inherited from two of the same base class?
Even
AParent::DoTheOtherThing();
doesn't help.  Now I'm asking - why is the class specified?  Are we avoiding
an override from this very class?  Are avoiding an override from an
intervening base class?  Are we selecting among DoTheOtherThing()s available
at the same level? Was it just put there as a sort of comment that this is
inherited directly from AParent?

It seems to me
a. getting rid of Virtual Inheritance
b. not permitting MI from two classes that define the same method
c. not permitting overloading
d. not permitting defaulting
gets rid of most of the confusion that arises in these cases.

Simply dumping MI in order to short-circuit the whole problem seems to me a perfect example of Throwing Out the Baby With the Bathwater.


agraham


September 03, 2001
>> > Private Inheritance: You don't get ISA, but you get implementation and
>> > data
>> > Only your closest 'friend' know where you got it
>> 
>> Hmmm, but what is here now the real difference to HASA?
> 
> It says the derived class has all the same HASA relationships as the parent, with out manually cutting and pasting code and forwarding method calls.  On the other hand, a pointer to the parent class cannot be assigned a reference to the child class.  It is for code reuse, but not polymorphism.

If it's private which calls should be forwarded? Is there any good example where private inheritance really makes sense? Against having a normal private field, HASA.

> Well, I can't say for sure myself.  I don't think it would be expensive though.  The implementation inheritance is just a matter the the compiler doing a cut and paste on the programmer's behalf.  The interface inheritance would be the same as inheriting from a pure virtual base class, even if it isn't pure virtual.  LX was pretty flexible too about these things.  It looked like LX would have performance problems because of some of it's features, but this isn't one I expected to cause problems.

Well I don't want to be harsh to cristopher, as the same goes for my own project. But how much code is actually coded in LX? From my own expirience I can tell a lot of things look good on paper first, but when you try to work with it, you discover it's 'cribbled' or has logical conflicts.

We'll just have to look how ideas proof themselfs in practice. It's the old science paradigm that in example the greeks did wrong. They theoritisied the whole time only, without paying attention to the expiriment. I think in basic the same ideology should be maintained also in programming environment, expirimients tell what's true or false, not theories.

> They simply recognized the C++ MI implementation had
> problems, so they lopped off a leg to fix a problem in the foot.
> Now let me get back to those divide by zero problems.  You know a naval
> ship was dead in the water as a result of a divide by zero.  The
> division operator is just too dangerous.  Besides, we can bit shift.
> It's the same as dividing by powers of two without all the dangers.

Yup that's a good argument MI has it's dangers, the division operator has it's dangers. But both have they're advantages, now you can scrap both and workaround them, or you can live with the danger. Division by zero is a result of another bug somewhere, not a problem itself.

I've a nicer example, the Ariane rocket. Had an integer overflow, and
suddendly changed it's mind from:
"I want to go up, I want to go up, I want to go up"
to "I want to turn around and thrust down", until the computer decided to
explode the rocket.

- Axel
September 03, 2001
Axel Kittenberger wrote in message <9mv2te$s4h$1@digitaldaemon.com>...
>We'll just have to look how ideas proof themselfs in practice.
>It's the old science paradigm that in example the greeks did wrong. They
>theoritisied the whole time only, without paying attention to the
>expiriment. I think in basic the same ideology should be maintained also in
>programming environment, expirimients tell what's true or false, not
>theories.

That is so true. I've had to redo D a couple times because I'd write a program, and find that what looked great in my head didn't work in a real program.