D - How to avoid code duplication in D? MI/CI/delegation/C&P?
- Yu Qian Zhou (99/99) Aug 29 2001 Admittedly Java's single inheritance is easy to implement, and simple to
- Walter (105/105) Aug 29 2001 The way to do it is to use interfaces:
- Dan Hursh (7/17) Aug 29 2001 Now I'm confused. Can a class inherit implementation code from an
- Walter (4/16) Sep 01 2001 If they are existing classes, then include them as members rather than a...
- Yu Qian Zhou (24/32) Sep 01 2001 But if the existing class has *many* methods you want to use, the
- Walter (4/6) Sep 02 2001 No, I haven't. I understand that not having MI will result in some code
- Axel Kittenberger (37/45) Sep 02 2001 I have to agree with Yu Qian, I've programmed some GUI's and java and
- kaffiene (22/68) Sep 02 2001 greater
- Axel Kittenberger (12/22) Sep 02 2001 At least for almost all the 'Listener' interfaces there are empty classe...
- Dan Hursh (45/51) Sep 02 2001 I think the is one of the interesting this C++ got convoluted. I like
- Axel Kittenberger (23/58) Sep 02 2001 Nothing is the answer to everything, and I dislike languages that presen...
- Dan Hursh (45/105) Sep 02 2001 Well, in my little world things are different ....
- Axel Kittenberger (23/48) Sep 02 2001 If it's private which calls should be forwarded? Is there any good examp...
- Walter (4/10) Sep 02 2001 That is so true. I've had to redo D a couple times because I'd write a
- Dan Hursh (17/69) Sep 02 2001 Nothing is coming to mind. I'm pretty sure I've had good uses for
- Sean L. Palmer (10/14) Oct 24 2001 I've always thought that if you divide by zero you should get infinity (...
- Axel Kittenberger (20/32) Oct 24 2001 Mathematically a division by zero does not give infinity, but is undefin...
- Russ Lewis (14/18) Oct 24 2001 Also remember that you can have "positive zero" and "negative zero" when...
- Iliya Peregoudov (25/25) Sep 07 2001 Why don't use another method for late methods binding?
- Walter (2/3) Sep 08 2001 Virtual tables have the advantage of fast execution speed.
- Iliya Peregoudov (7/12) Sep 09 2001 They're not so inefficient as it seems. The Objective-C run-time
- Axel Kittenberger (15/28) Sep 09 2001 That's but why use them if they are just a little slower? What advantage...
- Iliya Peregoudov (24/57) Sep 09 2001 The MAGIC_KEY mentioned is method index in vtable counted from (for
- Axel Kittenberger (41/63) Sep 09 2001 True, I didn't yet thought about vtables in combination with implementin...
- Walter (3/10) Sep 09 2001 I'd be a little surprised if gc makes the compiler slower. Most compilat...
- Axel Kittenberger (10/21) Sep 09 2001 I know, but gcc made advertising GC difficut, since it was one of the mo...
- Walter (12/15) Sep 09 2001 I've worked with Java and gc. GC can make a program faster, given:
- Axel Kittenberger (19/36) Sep 10 2001 I know that, but as said marketing and technics are two different things...
- a (22/30) Sep 10 2001 Java is a dismal sloth where I work. We had one decrepit machine
- Iliya Peregoudov (74/85) Sep 10 2001 vtable contains entries for all class methods, ie. both inherited and
- Axel Kittenberger (8/9) Sep 08 2001 Dispatch tables have only an advantage for loosly typed languages, or? A...
- Iliya Peregoudov (24/34) Sep 09 2001 A good description of dispatch tables can be found in the
- Bradeeoh (40/85) Sep 02 2001 I agree with Walter entirely about the enhanced readability and
- Charles D Hixson (16/38) Sep 02 2001 A part of what is involved is limited developer time. But if
- Angus Graham (31/44) Sep 02 2001 from
- Yu Qian Zhou (8/16) Aug 29 2001 What exactly do you mean?
- Richard Krehbiel (61/86) Aug 30 2001 Interfaces are fine and dandy, but the problem is, an interface doesn't
- Dan Hursh (14/132) Aug 29 2001 I believe the D way is code duplication. I personally don't like this,
- Eric Gerlach (18/30) Aug 30 2001 I was thinking about this this morning... you *do* lose a nice feature
- Axel Kittenberger (13/20) Aug 30 2001 I agree completly, I had no problems implementing MI for my compiler, I
- Dan Hursh (11/14) Aug 30 2001 Frankly, I find this hyper-idealist. It sounds good, but the cases I
- Sean L. Palmer (41/71) Oct 24 2001 I've got two words for you. Virtual and inheritance.
- Jan Knepper (4/5) Oct 24 2001 [ ... snip ... ]
- xiaochuang ling (20/23) Oct 26 2001 If you really want to know an elegant MI design, please read this tutori...
- xiaochuang ling (18/37) Oct 27 2001 I *sincerely* urge you to read the following page to find an clean (and
- xiaochuang ling (27/27) Oct 27 2001 Diamond MI:
- a (17/56) Oct 27 2001 Frankly, I don't think your idea will make it in, at least not any time
- xiaochuang ling (3/4) Oct 27 2001 First go to :
- a (3/11) Oct 27 2001 Same problem. I must have an out of date version of netscape.
- xiaochuang ling (7/8) Oct 27 2001 Even with the latest Netscape, you may still have problem :-) Many
Admittedly Java's single inheritance is easy to implement, and simple to use. But it does have some defect which sometimes force a programmer to duplicate code by 'copy & paste': Suppose I have two classes 'Car' and 'Dog', which *have already inherited* from some more important classes 'Vehicle' and 'Animal' respectively (let's assume that 'Vehicle' and 'Dog' do not have a common modifiable ancestor); now I want both these two classes to implement another interface 'Idable', how can I do it? Answer: =09 Java: Copy & Paste, code duplication !!! =09 C++: Multiple inheritance, no code duplication =09 C++: Textual code inclusion, no code duplication =09Eiffel: Multiple inheritance, no code duplication =09Sather: Semantic code inclusion, no code duplication Kiev: MI by delegation, no code duplication so what's the solution D can provide? =09 D: ??? code duplication ??? D borrowed DbC from Eiffel, perhaps it also worth to check the multiple inheritance mechanism of Eiffel, which is much cleaner than C++ (by renaming and redefinition). Or if you still feel strongly against MI, maybe you can also consider Sather's semantic code inclusion, or Kiev's forward-able delegation? Let me know your thoughts on this. YuQian Sample code: /*********************************************************************** Java: Copy & Paste, code duplication ***********************************************************************/ interface Idable { public void setId(int i); public void getId(); } class Car extends Vehicle implements Idable { private int id; public void setId(int i) { id =3D i; } =20 public void getId() { return i; } } class Dog=20 extends Animal implements Idable { private int id;=09=09=09=09// copy public void setId(int i) { id =3D i; } =09// & public void getId() { return i; } =09// paste! } /*********************************************************************** Kiev: Multiple inheritance by delegation, no code duplication ***********************************************************************/ class Id { private int id; public void setId(int i) { id =3D i; } =20 public void getId() { return i; } } class =A0Car=A0 extends Vehicle { =A0=A0=A0=A0forward=A0public=A0Id myId; // forward car.getId() to car.myI= d.getId() } class =A0Dog extends Animal { =A0=A0=A0=A0forward=A0public=A0Id myId; // forward dog.getId() to dog.myI= d.getId() } /*********************************************************************** C++: Multiple inheritance, no code duplication ***********************************************************************/ class Idable { private: int id; public: void setId(int i) { id =3D i; } =20 void getId() { return i; } }; class Car: public Vehicle, Idable {}; class Dog: public Animal, Idable {}; /*********************************************************************** C++: Textual code inclusion, no code duplication ***********************************************************************/ //--- begin file: id.ci --- private: int id; public: void setId(int i) { id =3D i; } =20 void getId() { return i; } //--- end file: id.ci --- class Car: public Vehicle { #include "id.ci" }; class Dog: public Animal { #include "id.ci" };
Aug 29 2001
The way to do it is to use interfaces: class Car : Vehicle, Idable { } Base classes after the first base class are interface classes. -Walter ----------------------------------------------------------------- Yu Qian Zhou wrote in message ... Admittedly Java's single inheritance is easy to implement, and simple to use. But it does have some defect which sometimes force a programmer to duplicate code by 'copy & paste': Suppose I have two classes 'Car' and 'Dog', which *have already inherited* from some more important classes 'Vehicle' and 'Animal' respectively (let's assume that 'Vehicle' and 'Dog' do not have a common modifiable ancestor); now I want both these two classes to implement another interface 'Idable', how can I do it? Answer: Java: Copy & Paste, code duplication !!! C++: Multiple inheritance, no code duplication C++: Textual code inclusion, no code duplication Eiffel: Multiple inheritance, no code duplication Sather: Semantic code inclusion, no code duplication Kiev: MI by delegation, no code duplication so what's the solution D can provide? D: ??? code duplication ??? D borrowed DbC from Eiffel, perhaps it also worth to check the multiple inheritance mechanism of Eiffel, which is much cleaner than C++ (by renaming and redefinition). Or if you still feel strongly against MI, maybe you can also consider Sather's semantic code inclusion, or Kiev's forward-able delegation? Let me know your thoughts on this. YuQian Sample code: /*********************************************************************** Java: Copy & Paste, code duplication ***********************************************************************/ interface Idable { public void setId(int i); public void getId(); } class Car extends Vehicle implements Idable { private int id; public void setId(int i) { id = i; } public void getId() { return i; } } class Dog extends Animal implements Idable { private int id; // copy public void setId(int i) { id = i; } // & public void getId() { return i; } // paste! } /*********************************************************************** Kiev: Multiple inheritance by delegation, no code duplication ***********************************************************************/ class Id { private int id; public void setId(int i) { id = i; } public void getId() { return i; } } class Car extends Vehicle { forward public Id myId; // forward car.getId() to car.myId.getId() } class Dog extends Animal { forward public Id myId; // forward dog.getId() to dog.myId.getId() } /*********************************************************************** C++: Multiple inheritance, no code duplication ***********************************************************************/ class Idable { private: int id; public: void setId(int i) { id = i; } void getId() { return i; } }; class Car: public Vehicle, Idable {}; class Dog: public Animal, Idable {}; /*********************************************************************** C++: Textual code inclusion, no code duplication ***********************************************************************/ //--- begin file: id.ci --- private: int id; public: void setId(int i) { id = i; } void getId() { return i; } //--- end file: id.ci --- class Car: public Vehicle { #include "id.ci" }; class Dog: public Animal { #include "id.ci" };
Aug 29 2001
Walter wrote:The way to do it is to use interfaces: class Car : Vehicle, Idable { } Base classes after the first base class are interface classes. -WalterNow I'm confused. Can a class inherit implementation code from an interface? If so then I've lost the difference between an interface and multiple inheritance. This also doesn't handle the case where Vehicle and Idable are existing classes (from a library?) that you would rather reuse instead of re-writing. Dan
Aug 29 2001
Dan Hursh wrote in message <3B8DD17F.CAD2F377 infonet.isl.net>...Walter wrote:No. An interface is just a function declaration, no code.The way to do it is to use interfaces: class Car : Vehicle, Idable { } Base classes after the first base class are interface classes.Now I'm confused. Can a class inherit implementation code from an interface?If so then I've lost the difference between an interface and multiple inheritance. This also doesn't handle the case where Vehicle and Idable are existing classes (from a library?) that you would rather reuse instead of re-writing.If they are existing classes, then include them as members rather than as bases.
Sep 01 2001
Walter wrote:But if the existing class has *many* methods you want to use, the programmer will need to wrapper all of them: class NewClass { ExistingClass dummy; // declare the member void foo(arg, ...) { return dummy.foo( arg ... ); } // delegate // repeat for *all* the methods of ExistingClass ... ... } This approach is very tedious and error-prone. That's the reason why Kiev introduce the 'forward' keyword: class NewClass { forward ExistingClass dummy; // newClass.foo(...) is automatically // forwarded to newClass.dummy.foo(...) // by the *compiler* } This solution is not perfect, but as long as there is no conflict it at least saves the programmers' labour, and it helps to reduce some possible programming errors. BTW, Walter, have you decided to introduce any better approach into D other than Java's single inheritance + interface + "Copy&Paste" ? YuQianIf so then I've lost the difference between an interface and multiple inheritance. This also doesn't handle the case where Vehicle and Idable are existing classes (from a library?) that you would rather reuse instead of re-writing.If they are existing classes, then include them as members rather than as bases.
Sep 01 2001
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.
Sep 02 2001
Yu Qian Zhou wrote in message ...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. - AxelBTW, 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.
Sep 02 2001
"Axel Kittenberger" <axel dtone.org> wrote in message news:9mst9n$2o41$1 digitaldaemon.com...greaterYu 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 theoftenunderstandability 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, butonly 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.Ifthe 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 thanimplementingthe '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 specifyfromwhich 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'restillfar more powerfull than single inheritence would provide. - Axel
Sep 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
Sep 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
Sep 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 itHmmm, 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
Sep 02 2001
Axel Kittenberger wrote:Well, in my little world things are different .... :-)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)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.Private Inheritance: You don't get ISA, but you get implementation and data Only your closest 'friend' know where you got itHmmm, but what is here now the real difference to 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.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++)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.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.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.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.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.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 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. DanI'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.
Sep 02 2001
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.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.Private Inheritance: You don't get ISA, but you get implementation and data Only your closest 'friend' know where you got itHmmm, but what is here now the real difference to 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
Sep 02 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.
Sep 02 2001
Axel Kittenberger wrote:Nothing is coming to mind. I'm pretty sure I've had good uses for private inheritance in previous projects, but not many. It would be a lot more useful if the method retained their access classification and you just did get the ISA relationship from the base class.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.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.Private Inheritance: You don't get ISA, but you get implementation and data Only your closest 'friend' know where you got itHmmm, but what is here now the real difference to HASA?True, it's a new idea, just worked better in my head than the styles of inheritance in C++. For that matter I can't remember if LX had access control on members.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.True, but it is good that there are still folks that are theorizing. :-)Geez! Maybe we should just use variable length text to represent numbers. Of course that still doesn't fix divide by zero. I still say we drop it. DanThey 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.
Sep 02 2001
I've always thought that if you divide by zero you should get infinity (if the dividend was positive) or negative infinity (if the dividend was negative). With modulo by zero the answer is always zero. I'm not so sure I agree with my old line of thinking these days though. It's probably better to organize the code against preventing division by zero than by responding to it after the fact (may save a division, but requires some comparisons first, as well as some knowledge about the limitations of your floating point representation). I just don't know, I'm so used to DBZ by now it doesn't bother me anymore. SeanGeez! Maybe we should just use variable length text to represent numbers. Of course that still doesn't fix divide by zero. I still say we drop it. Dan
Oct 24 2001
Sean L. Palmer wrote:I've always thought that if you divide by zero you should get infinity (if the dividend was positive) or negative infinity (if the dividend was negative). With modulo by zero the answer is always zero. I'm not so sure I agree with my old line of thinking these days though. It's probably better to organize the code against preventing division by zero than by responding to it after the fact (may save a division, but requires some comparisons first, as well as some knowledge about the limitations of your floating point representation).Mathematically a division by zero does not give infinity, but is undefined. A devision of _nearly_ zero gives _nearly_ infinity. Take following sentence out of: a / b = c --follows--> a = b * c I guess thats a pretty *dough* sentence :o) Take in example the proposal: 2 / 0 = infinity then it would have to be that 0 * inifity = ? 2 ? --- See? Infinity is not quite right. Maths can calculate with _nearly_ zero and _nearly_ infinity, like the a * sin (x) lim --------- x -> 0 x Would give mathematically a defined result, but hence we do programming here not hardcore maths :o)Geez! Maybe we should just use variable length text to represent numbers. Of course that still doesn't fix divide by zero. I still say we drop it.Division by zero is an error, and should raise an exception, a hardware trap,etc.
Oct 24 2001
Axel Kittenberger wrote:Maths can calculate with _nearly_ zero and _nearly_ infinity, like the a * sin (x) lim --------- x -> 0 xAlso remember that you can have "positive zero" and "negative zero" when dealing with limits: abs(x) lim ------- = 1 x -> 0+ x abs(x) lim ------- = -1 x -> 0- x -- The Villagers are Online! villagersonline.com .[ (the fox.(quick,brown)) jumped.over(the dog.lazy) ] .[ (a version.of(English).(precise.more)) is(possible) ] ?[ you want.to(help(develop(it))) ]
Oct 24 2001
Why don't use another method for late methods binding? Multiple inheritance in C++ is so clumsy due to using of virtual tables. There is another method used in Objective-C -- dispatching tables, also known as selector tables. Objective-C is loosely typed language that support completely anonymous object type (id). But this is done just to make it more similar to Smalltalk. It is possible to make a strictly typed language that use dispatching tables. [Dispatching table for the class contains entries only for those methods, that had been defined in this class. It also contains a link to superclass dispatch table. If required method is not found in the its class dispatch table it will be searched in superclass dispatch table and so on.] Objective-C doesn't support multiple inheritance. But its model can be easily extended to support it -- just let the dispatch table contain multiple links to superclasses. Dispatch tables also convenient for various GUI frameworks that define palymorphing methods for event handlers. The common problem is that there are too many events to be handled. If you make method for each handler the vtables grow extremely for each GUI framework class. This is because most frameworks doesn't use virtual methods for event handlers (for example, Borland VCL and OWL use dynamic methods that use exactly the same dispatch tables, MFC uses tables that are similar to dispatch tables). So, why don't use dispatch tables instead of virtual tables? -- iliyap
Sep 07 2001
Iliya Peregoudov wrote in message <3B98B78E.7232 mail.ru>...So, why don't use dispatch tables instead of virtual tables?Virtual tables have the advantage of fast execution speed.
Sep 08 2001
Walter wrote:Iliya Peregoudov wrote in message <3B98B78E.7232 mail.ru>...They're not so inefficient as it seems. The Objective-C run-time system, for example, maintains a method cache for ecach class. When the method is called for the object it is cached in the object's class method cache. When the method called again it looked up in the cache. Method cache is a flat table so cache lookups are just a little slower than vtable lookups.So, why don't use dispatch tables instead of virtual tables?Virtual tables have the advantage of fast execution speed.
Sep 09 2001
Iliya Peregoudov wrote:Walter wrote:That's but why use them if they are just a little slower? What advantage do they bring if weak type binding is not supported at all, just a little slower for what? As far I understood the memory occupied by the one super-table is not less than the sum of all vtables for every object. Why do caching if the compiler can already write the precalculated value into the assembler code as vtable? A vtable call constist of vtable[MAGIC_KEY](arguments), so it's composed of vtable + MAGIC_KEY, get content of, call. That's are 3 assembler level commands. All I read about dispatch tables was only pure hiping on how they are cool, and how vtables are bad, but without no facts in the background. Of how much assembler compositions does a dispatch call take less than a vtable call? Or maybe a little example of two or three classes, where a dispatch table will take less memory than the 3 vtables. - AxelIliya Peregoudov wrote in message <3B98B78E.7232 mail.ru>...They're not so inefficient as it seems. The Objective-C run-time system, for example, maintains a method cache for ecach class. When the method is called for the object it is cached in the object's class method cache. When the method called again it looked up in the cache. Method cache is a flat table so cache lookups are just a little slower than vtable lookups.So, why don't use dispatch tables instead of virtual tables?Virtual tables have the advantage of fast execution speed.
Sep 09 2001
Axel Kittenberger wrote:Iliya Peregoudov wrote:The MAGIC_KEY mentioned is method index in vtable counted from (for example) zero. When a class inherits from two classes (multiple inheritance) method indexes overlap each other. So you'll need two vtables. If the class inherits from classes that already inherited from other classes (and so on) you'll end up with a great number of vtables for the class. This can be avoided if each method in the system takes its own unique MAGIC_KEY. For example, doSomething(int, char[]) is assigned 1001 (system can contain hungreds of classes with thousands of different methods). So if the class implemets method doSomething(int, char[]) it already has vtable 1002 items long (al least). Most slots of vtable will be unfilled. When using dispatch tables each method takes its own unique MAGIC_KEY named selector. But the dispatch table is not a linear array, but a hash, where selector is a key and method address is a value. Moreover this hash contains only those selector:method pairs that are defined in the class but not those that inherited. Cache contains only those selector:method pairs that are used at runtime for this class, not all selector:method pairs in the system. Hash lookups are slower then linear array lookups. But garbage collection is a also not so efficient than manual memory management. Why garbage collected programs are faster and less error prone than those using manual memory management?Walter wrote:That's but why use them if they are just a little slower? What advantage do they bring if weak type binding is not supported at all, just a little slower for what? As far I understood the memory occupied by the one super-table is not less than the sum of all vtables for every object. Why do caching if the compiler can already write the precalculated value into the assembler code as vtable? A vtable call constist of vtable[MAGIC_KEY](arguments), so it's composed of vtable + MAGIC_KEY, get content of, call. That's are 3 assembler level commands. All I read about dispatch tables was only pure hiping on how they are cool, and how vtables are bad, but without no facts in the background. Of how much assembler compositions does a dispatch call take less than a vtable call? Or maybe a little example of two or three classes, where a dispatch table will take less memory than the 3 vtables. - AxelIliya Peregoudov wrote in message <3B98B78E.7232 mail.ru>...They're not so inefficient as it seems. The Objective-C run-time system, for example, maintains a method cache for ecach class. When the method is called for the object it is cached in the object's class method cache. When the method called again it looked up in the cache. Method cache is a flat table so cache lookups are just a little slower than vtable lookups.So, why don't use dispatch tables instead of virtual tables?Virtual tables have the advantage of fast execution speed.
Sep 09 2001
The MAGIC_KEY mentioned is method index in vtable counted from (for example) zero. When a class inherits from two classes (multiple inheritance) method indexes overlap each other. So you'll need two vtables. If the class inherits from classes that already inherited from other classes (and so on) you'll end up with a great number of vtables for the class.True, I didn't yet thought about vtables in combination with implementing differend interfaces at the same time. So the "problem" even exists with java-like SI inheritince not even only in multi-inheritance.This can be avoided if each method in the system takes its own unique MAGIC_KEY. For example, doSomething(int, char[]) is assigned 1001 (system can contain hungreds of classes with thousands of different methods). So if the class implemets method doSomething(int, char[]) it already has vtable 1002 items long (al least). Most slots of vtable will be unfilled."Most slots of vtable will be unfilled." That's false. In a vtable system not every function will have a global unique ID. Every function has a unique ID in the vtable for the class that started a polymorhpic function. If a class has 7 virtual functions it's vtable will be 7 entries long. If a class implements two interfaces each with 10 different virtual functions, it has 2 vtables with each 10 entries, so it are 20 entries in summeration. Having 1000 unfilled entries is not true, you can watch C++'s vtables in example in ddd/gdb in the debugger in action. The tables had always as much entries as I implemented virtual functions. Why can ID's be duplicated? Since the compiler know in the call to foo() that this function is in the foo interface, so it can take the id for the foo vtable.When using dispatch tables each method takes its own unique MAGIC_KEY named selector. But the dispatch table is not a linear array, but a hash, where selector is a key and method address is a value. Moreover this hash contains only those selector:method pairs that are defined in the class but not those that inherited. Cache contains only those selector:method pairs that are used at runtime for this class, not all selector:method pairs in the system.Ahh, I understand know.... still I think system is pretty good for loosly bindend language. For strong typed ones, where all possiblites can be precalculated at compiletime I see neither a speed nor a memory gain. Take the class bork that implemnts the interfaces cork and dork. cork and dork have 10 functions. Then the tables use at the end: dork: 10 entries cork: 10 entries bork: 20 entries -- 50 entries in summeration. Now with a dispatch table imagined to be flat it would be 20 functions for 3 classes, so it are 60 entries. Okay now with hashing you can save the nulls. so the logic is not class but function based. So 10 functions from dork have to be counted 2 times (for dork and bork), and the 10 functions from cork are also counted two times (for cork and bork). So it are hmmm, 40 entries. Okay I understand :) Still I'm not convinced that the memory requirements pay that much of the hazzle for having to hash.But garbage collection is a also not so efficient than manual memory management. Why garbage collected programs are faster and less error prone than those using manual memory management?Well this is a whole science itself. Garbadge collected programs -can- be faster then convetional ones. Since a lot of object coping can be saved sometimes.But this is not a must be. Especially gcc 3.0 vs 2.95 did not convince me. 3.0 uses now GC inside, but in summeration with all other edits it compiler far slower than 2.95. However to say it's due to the GC is false, since it's the sum of a lot of new stuff, and more sensetive warning checking etc. - Axel
Sep 09 2001
Well this is a whole science itself. Garbadge collected programs -can- be faster then convetional ones. Since a lot of object coping can be saved sometimes.But this is not a must be. Especially gcc 3.0 vs 2.95 did not convince me. 3.0 uses now GC inside, but in summeration with all other edits it compiler far slower than 2.95. However to say it's due to the GC is false, since it's the sum of a lot of new stuff, and more sensetive warning checking etc.I'd be a little surprised if gc makes the compiler slower. Most compilations will not need more than available memory to compile, and if the gc is tuned to that, it will rarely need to actually run a collection.
Sep 09 2001
Walter wrote:I know, but gcc made advertising GC difficut, since it was one of the most famous projects that really used garbadge collection, and with this release it turned out to compile at least double as long :/ I understand that it has nothing do to with each other, but it's a slap on "marketing". Try to call really a well-known project that runs fast with GC. Tell the people gcc 3.0 and you make a fool of yourself. Say java and you'll have to laugh yourself. I don't know of any others, and I understand the reasons behind speed penality are to be searched other where, but try to tell this :/ - AxelWell this is a whole science itself. Garbadge collected programs -can- be faster then convetional ones. Since a lot of object coping can be saved sometimes.But this is not a must be. Especially gcc 3.0 vs 2.95 did not convince me. 3.0 uses now GC inside, but in summeration with all other edits it compiler far slower than 2.95. However to say it's due to the GC is false, since it's the sum of a lot of new stuff, and more sensetive warning checking etc.I'd be a little surprised if gc makes the compiler slower. Most compilations will not need more than available memory to compile, and if the gc is tuned to that, it will rarely need to actually run a collection.
Sep 09 2001
Axel Kittenberger wrote in message <9ngagf$1isq$1 digitaldaemon.com>...Say java and you'll have to laugh yourself. I don't know of any others, and I understand the reasons behind speed penality are to be searched other where, but try to tell this :/I've worked with Java and gc. GC can make a program faster, given: 1) write code that makes use of gc - for example, in C, people frequently copy strings to avoid memory ownership bugs. With gc, copy a reference, not the data. 2) close cooperation with the language. This, of course, doesn't work with C++. 3) much temporary generation in C++ can go away, again because of (1). 4) Java programs can be slow because the String class is inefficient, and because in general the language requires a lot more heap allocated objects than C/C++. File I/O is slow in Java, and of course, a poorly implemented JIT or GC will also make it slow <g>.
Sep 09 2001
Walter wrote:Axel Kittenberger wrote in message <9ngagf$1isq$1 digitaldaemon.com>...I know that, but as said marketing and technics are two different things, just put you're finger on an open project that runs fast and uses GC :/Say java and you'll have to laugh yourself. I don't know of any others, and I understand the reasons behind speed penality are to be searched other where, but try to tell this :/I've worked with Java and gc. GC can make a program faster, given: 1) write code that makes use of gc - for example, in C, people frequently copy strings to avoid memory ownership bugs. With gc, copy a reference, not the data.3) much temporary generation in C++ can go away, again because of (1).I guess you mean what the compile generates himself in background, or? Don't know some C++ things are a mystery for myself, and I believe a lot of constructions are wired because they wanted to still use existing linkers. I believe that if the final linker is aware of some language features a lot of optimization and simplification could take place here (like realöy functional inling, or the whole dynamic-type stuff could be done so much simpler if only the final linker would assign IDs, instead of having to output the whole class descriptions into the object file.4) Java programs can be slow because the String class is inefficient, and because in general the language requires a lot more heap allocated objects than C/C++. File I/O is slow in Java, and of course, a poorly implemented JIT or GC will also make it slow <g>.Java programs are slower because they are still interpreted/JIT compiled. However I must hardly defend java here, suns hotspot vm (jdk 1.3) or jre or however their marketing calls it today is the fastest vm I've ever seen, and this goes globally not even for java. It runs blazing fast for having to JIT compile / interpred in background, and one can today even already render graphics in a modern java VM with reasonable speed. - Axel
Sep 10 2001
Axel Kittenberger wrote:Walter wrote:Java programs are slower because they are still interpreted/JIT compiled. However I must hardly defend java here, suns hotspot vm (jdk 1.3) or jre or however their marketing calls it today is the fastest vm I've ever seen, and this goes globally not even for java. It runs blazing fast for having to JIT compile / interpred in background, and one can today even already render graphics in a modern java VM with reasonable speed.Java is a dismal sloth where I work. We had one decrepit machine running several server processes in C. Due to politics we switched to java and now each server has to have its own bleeding edge machine to crawl with insufferable performance. I think it's more than the string implementation. I like what hot java does, but if may echo the words of another, it's a shame we don't do more with self modifying code. Using hot java to make up for java's pathetic performance is as bad as the arguments that have been used to justify micro-kernels. Any optimization hoops you leap backwards through to try to make the micro-kernel tolerable could be done to the monolith to further humiliate the micro-kernel's (lack of) performance. If we could devise smarter systems for optimizing running native code it would help java and native code. I had a bit of hope with Transmeta's work, but it does not seem to be their focus. OK, so most of the arguments against micro-kernels are based on mach which is about as micro as a gas giant. Likewise, java's VM wasn't designed for performance. Well, they didn't get it, and everything since is just an attempted apology. Dan
Sep 10 2001
Axel Kittenberger wrote:Take the class bork that implemnts the interfaces cork and dork. cork and dork have 10 functions. Then the tables use at the end: dork: 10 entries cork: 10 entries bork: 20 entries -- 50 entries in summeration. Now with a dispatch table imagined to be flat it would be 20 functions for 3 classes, so it are 60 entries.vtable contains entries for all class methods, ie. both inherited and newly defined in the class. Some of the inherited methods can be overriden -- this doesn't increase vtable size. vtable size only increased when new methods added. In current D spec each class also defines an interface. Each class MUST inherit from one class and MAY implement any number of interfaces. Now imagine class A that inherits from B. B is inherits from C and implements D and E. +-----+ +-----+ +-----+ | C | | D | | E | +-----+ +-----+ +-----+ |inher | | +-----+ | | | B |<-impl-/<-impl----+ +-----+ |inher +-----+ | A | +-----+ vtables for class A: vtable1 - contains new A + new B + all D + all E + all C methods, vtable2 - contains all D methods, vtable3 - contains all E methods. vtable1 implements interfaces A, B, C. vtable2 implements D interface. vtable3 implements E interface. vtables for class B: vtable1 - contains new B + all D + all E + all C methods, vtable2 - contains all D methods, vtable3 - contains all E methods. vtable1 implements interfaces B and C. vtable2 implements D interface. vtable3 implements E interface. Lets imagine that vtables for classes C, D, E are trivial -- just one vtable -- classes C, D, E are root classes. Now lets imagine that each class implements 10 new methods and count the size of the tables: E: 10 entries D: 10 entries C: 10 entries B: (vt1=40)+(vt2=10)+(vt3=10)=60 entries A: (vt1=50)+(vt2=10)+(vt3=10)=70 entries all: 160 entries Now try using dispatch tables. Dispatch table for class contains entries for newly defined methods and for overriden methods (not all inherited). So we can calculate minimul and maximum dispatch table sizes. Minimum size (no inherited methods overriden): E: 10 D: 10 C: 10 B: 10 A: 10 all: 50 Maximum size (all iherited methods overriden): E: 10 D: 10 C: 10 B: (inherited=30)+(new=10)=40 D: (inherited=40)+(new=10)=50 all: 120 Actual size is somewhat in the middle (50% of inherited methods are overriden): (120+50)/2=85 This value depends on what percentage of methods are overriden in typical project. For GUI frameworks it typically much less (about 20%). So memory consumption is lesser then for vtables. As I already said another advantage of dispatch tables is that we need only one table per class, not a vtable per each interface class inherits or implements. Implementation of such single-table dispatching is clean and easily understandable. For me, I don't understand how to implement multiple vtables for class. Should it be vtable[INTERFACE_INDEX][METHOD_INDEX]? But any future class can potentially implement any interface, so how to generate consistent INTERFACE_INDEXes?
Sep 10 2001
So, why don't use dispatch tables instead of virtual tables?Dispatch tables have only an advantage for loosly typed languages, or? As far I understood they don't bring any benefits for strong typed languages, where all type conflicts can be determined at compiletime, so the compiler can precalculate all the possible calling situations and thus vtables are more effective. After all for a vtable call you only require to call a function pointer from an array. I searched a little but found nowhere a nice description how dispatch tables actually work :/ - Axel
Sep 08 2001
Axel Kittenberger wrote:A good description of dispatch tables can be found in the "Object-Oriented Programming and the Objective-C Language", Chapter 2, "The Objective-C Language", under "How Messaging Works". This book can be downloaded as PDF file from http://www.gnustep.org/resources/documentation/ObjectivCBook.pdf (480K) And I can't find a nice description how virtual tables work when multiple inheritance come into the scene :/ But (as I understand) it needs multiple virtual tables per class. The advantage of dispatch tables is that we always can put all the things in a single table. Another advantage is when using the language for GUI frameworks. There is no need to invent other meens of events transport -- all events can be mapped to messages. No more Object Pascal dynamic methods bounded to cm_XXX constants, MFC event handler tables, Qt signals -- all is done using intrinsic language features.So, why don't use dispatch tables instead of virtual tables?Dispatch tables have only an advantage for loosly typed languages, or? As far I understood they don't bring any benefits for strong typed languages, where all type conflicts can be determined at compiletime, so the compiler can precalculate all the possible calling situations and thus vtables are more effective. After all for a vtable call you only require to call a function pointer from an array. I searched a little but found nowhere a nice description how dispatch tables actually work :/
Sep 09 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...greaterYu 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 theoftenunderstandability 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, butonly 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.Ifthe 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 thanimplementingthe '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 justinheritboth 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 specifyfromwhich 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'restillfar more powerfull than single inheritence would provide. - Axel
Sep 02 2001
Axel Kittenberger wrote: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 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.Yu Qian Zhou wrote in message ...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. - AxelBTW, 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.
Sep 02 2001
"Axel Kittenberger" <axel dtone.org> wroteI think single inheritence was an expiriment, worth taking altough. But looking at the results my impression is it failed. Why can't I justinheritboth 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 specifyfromwhich 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'restillfar 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
Sep 02 2001
The way to do it is to use interfaces: class Car : Vehicle, Idable { } Base classes after the first base class are interface classes. -WalterWhat exactly do you mean? "The way to do it is to use interfaces ... " ... to *introduce* code duplication by Copy&Paste like Java ? But my question is "How to *avoid* ..." ... code duplication in D ? :-) YuQian
Aug 29 2001
Interfaces are fine and dandy, but the problem is, an interface doesn't carry any *code* with it. Just an interface spec. A Java example: interface A { void DoRight(int a); // Declares that any class that implements A // will provide DoRight. No implementation. } class Z implements A { void DoRight(int a) { // Imagine here 160 lines of complex implementation code. } } class Y implements A { void DoRight(int a) { // 160 lines of complex implementation code. // No matter that it may be *identical* to Z.DoRight... } } Duplication of source code. The worst possible thing for maintenance. A way to solve this in Java is to declare *another* class... class H { public void DoRight(int a) { // 160 lines of, well, you know } } class Z implements A { H helper = new H; public void DoRight(int a) { helper.DoRight(a); } } class Y implements A { H helper = new H; void DoRight(int a) { helper.DoRight(a); } } This is less convenient than multiple inheritance. This could be alleviated if A.DoRight could have a default implementation. But since an interface cannot declare any instance variables, this may be somewhat troublesome. Why not allow interfaces in D to have instance data, and interface methods to have implementations? Then it would be as convenient as multiple inheritance. Interfaces would still be distinct from classes, so it's not *quite* M-I. "Walter" <walter digitalmars.com> wrote in message news:9mkido$q2i$1 digitaldaemon.com...The way to do it is to use interfaces: class Car : Vehicle, Idable { } Base classes after the first base class are interface classes. -Walter ----------------------------------------------------------------- Yu Qian Zhou wrote in message ... Admittedly Java's single inheritance is easy to implement, and simple to use. But it does have some defect which sometimes force a programmer to duplicate code by 'copy & paste': Suppose I have two classes 'Car' and 'Dog', which *have already inherited* from some more important classes 'Vehicle' and 'Animal' respectively (let's assume that 'Vehicle' and 'Dog' do not have a common modifiable ancestor); now I want both these two classes to implement another interface 'Idable', how can I do it? Answer: Java: Copy & Paste, code duplication !!! C++: Multiple inheritance, no code duplication C++: Textual code inclusion, no code duplication Eiffel: Multiple inheritance, no code duplication Sather: Semantic code inclusion, no code duplication Kiev: MI by delegation, no code duplication so what's the solution D can provide? D: ??? code duplication ???-- Richard Krehbiel, Arlington, VA, USA rich kastle.com (work) or krehbiel3 home.com (personal)
Aug 30 2001
Unfortunately, the helper class is the way to factor out the common code. Another way is to embed an instance of A as a member of Y and Z. -Walter "Richard Krehbiel" <rich kastle.com> wrote in message news:9ml9gr$1844$1 digitaldaemon.com...Interfaces are fine and dandy, but the problem is, an interface doesn't carry any *code* with it. Just an interface spec. A Java example: interface A { void DoRight(int a); // Declares that any class that implements A // will provide DoRight. No implementation. } class Z implements A { void DoRight(int a) { // Imagine here 160 lines of complex implementation code. } } class Y implements A { void DoRight(int a) { // 160 lines of complex implementation code. // No matter that it may be *identical* to Z.DoRight... } } Duplication of source code. The worst possible thing for maintenance. A way to solve this in Java is to declare *another* class... class H { public void DoRight(int a) { // 160 lines of, well, you know } } class Z implements A { H helper = new H; public void DoRight(int a) { helper.DoRight(a); } } class Y implements A { H helper = new H; void DoRight(int a) { helper.DoRight(a); } } This is less convenient than multiple inheritance. This could be alleviated if A.DoRight could have a default implementation. But since an interface cannot declare any instance variables, this may be somewhat troublesome. Why not allow interfaces in D to have instance data, and interface methods to have implementations? Then it would be as convenient as multiple inheritance. Interfaces would still be distinct from classes, so it's not *quite* M-I. "Walter" <walter digitalmars.com> wrote in message news:9mkido$q2i$1 digitaldaemon.com...inherited*The way to do it is to use interfaces: class Car : Vehicle, Idable { } Base classes after the first base class are interface classes. -Walter ----------------------------------------------------------------- Yu Qian Zhou wrote in message ... Admittedly Java's single inheritance is easy to implement, and simple to use. But it does have some defect which sometimes force a programmer to duplicate code by 'copy & paste': Suppose I have two classes 'Car' and 'Dog', which *have alreadyfrom some more important classes 'Vehicle' and 'Animal' respectively (let's assume that 'Vehicle' and 'Dog' do not have a common modifiable ancestor); now I want both these two classes to implement another interface 'Idable', how can I do it? Answer: Java: Copy & Paste, code duplication !!! C++: Multiple inheritance, no code duplication C++: Textual code inclusion, no code duplication Eiffel: Multiple inheritance, no code duplication Sather: Semantic code inclusion, no code duplication Kiev: MI by delegation, no code duplication so what's the solution D can provide? D: ??? code duplication ???-- Richard Krehbiel, Arlington, VA, USA rich kastle.com (work) or krehbiel3 home.com (personal)
Aug 30 2001
Walter wrote:Unfortunately, the helper class is the way to factor out the common code.That is assuming that you wrote A and can hence rewrite it as an interface and helper. Convenience (or a lack there of) aside, you are in trouble if the vendor shipped a class.Another way is to embed an instance of A as a member of Y and Z. -WalterAt least with the helper (assuming you can do it) you get polymorphism and an error if a new method gets added to the interface. This is a punt. Dan
Aug 30 2001
I believe the D way is code duplication. I personally don't like this, but it was a design decision in order to prevent the inheritance mess that C++ owes us an apology for. I know C++'s syntax and semantics are rather nasty and I hear it makes the compiler internals a mess so I can't complain if MI is left out. I just dislike how some folk pretend that there isn't a loss of functionality without MI. I don't know if D will support MI since there has been a strong reaction against, but if you know of a better way that it could be implemented without sacrificing the other design goals of D (including an easy to implement compiler), I love to hear it. Since the time that I only knew fortran 77 and Commodore basic, I've want MI functionality. I just didn't know what it was called until I learn C++. Dan Yu Qian Zhou wrote:Admittedly Java's single inheritance is easy to implement, and simple to use. But it does have some defect which sometimes force a programmer to duplicate code by 'copy & paste': Suppose I have two classes 'Car' and 'Dog', which *have already inherited* from some more important classes 'Vehicle' and 'Animal' respectively (let's assume that 'Vehicle' and 'Dog' do not have a common modifiable ancestor); now I want both these two classes to implement another interface 'Idable', how can I do it? Answer: Java: Copy & Paste, code duplication !!! C++: Multiple inheritance, no code duplication C++: Textual code inclusion, no code duplication Eiffel: Multiple inheritance, no code duplication Sather: Semantic code inclusion, no code duplication Kiev: MI by delegation, no code duplication so what's the solution D can provide? D: ??? code duplication ??? D borrowed DbC from Eiffel, perhaps it also worth to check the multiple inheritance mechanism of Eiffel, which is much cleaner than C++ (by renaming and redefinition). Or if you still feel strongly against MI, maybe you can also consider Sather's semantic code inclusion, or Kiev's forward-able delegation? Let me know your thoughts on this. YuQian Sample code: /*********************************************************************** Java: Copy & Paste, code duplication ***********************************************************************/ interface Idable { public void setId(int i); public void getId(); } class Car extends Vehicle implements Idable { private int id; public void setId(int i) { id = i; } public void getId() { return i; } } class Dog extends Animal implements Idable { private int id; // copy public void setId(int i) { id = i; } // & public void getId() { return i; } // paste! } /*********************************************************************** Kiev: Multiple inheritance by delegation, no code duplication ***********************************************************************/ class Id { private int id; public void setId(int i) { id = i; } public void getId() { return i; } } class Car extends Vehicle { forward public Id myId; // forward car.getId() to car.myId.getId() } class Dog extends Animal { forward public Id myId; // forward dog.getId() to dog.myId.getId() } /*********************************************************************** C++: Multiple inheritance, no code duplication ***********************************************************************/ class Idable { private: int id; public: void setId(int i) { id = i; } void getId() { return i; } }; class Car: public Vehicle, Idable {}; class Dog: public Animal, Idable {}; /*********************************************************************** C++: Textual code inclusion, no code duplication ***********************************************************************/ //--- begin file: id.ci --- private: int id; public: void setId(int i) { id = i; } void getId() { return i; } //--- end file: id.ci --- class Car: public Vehicle { #include "id.ci" }; class Dog: public Animal { #include "id.ci" };
Aug 29 2001
I believe the D way is code duplication. I personally don't like this, but it was a design decision in order to prevent the inheritance mess that C++ owes us an apology for. I know C++'s syntax and semantics are rather nasty and I hear it makes the compiler internals a mess so I can't complain if MI is left out. I just dislike how some folk pretend that there isn't a loss of functionality without MI. I don't know if D will support MI since there has been a strong reaction against, but if you know of a better way that it could be implemented without sacrificing the other design goals of D (including an easy to implement compiler), I love to hear it. Since the time that I only knew fortran 77 and Commodore basic, I've want MI functionality. I just didn't know what it was called until I learn C++.I was thinking about this this morning... you *do* lose a nice feature without MI. The real reason that I think that's the case is because it's a bitch to get it right. There are so may cases of conflicting functions... how do you resolve them and know which function to call? Suppose classes A and B both define foo(). C inherits from both A and B, which one do you inherit? What if foo() in A and B were redefined from a common ancestor, Z? What if one of them is final? There's just too much to think about. Here's my thought: What about allowing MI, as long as there are *no* conflicts? None. Whatsoever. If there are, it's an error. That allows the useful part of MI without getting into the mess. Now, if anyone has a good way of resolving conflicts (I hear Eiffel is good at that) I think we'd all be willing to hear it. But disallowing conflicts shouldn't affect the compiler too much (it just fills in the vtable it was going to leave blank), and it gives ua a nice feature to play with. Comments on that? Eric
Aug 30 2001
Now, if anyone has a good way of resolving conflicts (I hear Eiffel is good at that) I think we'd all be willing to hear it. But disallowing conflicts shouldn't affect the compiler too much (it just fills in the vtable it was going to leave blank), and it gives ua a nice feature to play with. Comments on that?I agree completly, I had no problems implementing MI for my compiler, I simply forbidded conflict and it I've no problems with it. I don't know why all people damm MI, just because C++ was so a bad implementation of it. In my opinion interfaces are just a workaround around missing MI. I know java puriest will say it isn't, but I believe it is. Especially as in java you've always classes comming in double, as interface and as empty object for inheritince it shows it weakness. Like all the InputListeners, you either can use an default Listener only overriding the functions you're interested in, or you must implement the whole interface sometimes necesarry because you inherit already from something else. Resulting have dozends of meaninlings code lines, just because java wants it so. I think interfaces are just a lame excuse for not having MI. - Axel
Aug 30 2001
Eric Gerlach wrote:Here's my thought: What about allowing MI, as long as there are *no* conflicts? None. Whatsoever. If there are, it's an error. That allows the useful part of MI without getting into the mess.Frankly, I find this hyper-idealist. It sounds good, but the cases I care about most is inheriting from class I didn't write. I don't want to rewrite the code as an interface and copy the implementations. I don't want to rewrite them because the both have a toString function. Let me write my own or address the conflict. I suppose I can agree to forcing conflicts to being resolved in the inheriting class so the compiler is left trying to guess, but I would rather have the total deficiency than to have a solution that is too idealized to be of any practical value. Dan
Aug 30 2001
I've got two words for you. Virtual and inheritance. Say you have this situation: class A { } class B : A { } class C : A { } class D : B, C { } Now how many instances of A are in D? Two? Or one... but which one, the one from B or the one from C? What if both B and C try to use the same A? Will it behave ok, or will it be a bug? Can you tell the compiler which one to keep, or to merge the two, or to keep both and have duplicate, possibly conflicting data? How do clients figure out how to get a pointer to the A part of a D? There is runtime overhead for the solution C++ came up with to allow one to specify that the compiler should merge the A's together. MI really just opens up a whole can of worms that is just better left closed. I've argued the opposite point too, years ago, but lately I really do agree that if you need MI to do something besides exposing interfaces, you could most of the time be better off rethinking your class hierarchy because it's likely flawed. It's easy to abuse OOP when you start down a flawed path and to make it work you have to tie up some loose ends... MI enables both these things, but they're both unnecessary. MI is appealing conceptually, until you've had to throw away a few spaghetti projects because you couldn't disentangle them. A way to auto generate forwarding functions would be nice though, save a lot of typing. Maybe as part of the inheritance mechanism you could say you want to implement an interface, but have all functionality requests *by default* be routed to a member object which exposes that same interface. Of course you could then override any of them you cared to... that'd enable some very MI-like objects, but it's all has-a, not is-a; much less complicated. Sean "Eric Gerlach" <egerlach canada.com> wrote in message news:3B8E33D8.3060502 canada.com...I believe the D way is code duplication. I personally don't like this, but it was a design decision in order to prevent the inheritance mess that C++ owes us an apology for. I know C++'s syntax and semantics are rather nasty and I hear it makes the compiler internals a mess so I can't complain if MI is left out. I just dislike how some folk pretend that there isn't a loss of functionality without MI. I don't know if D will support MI since there has been a strong reaction against, but if you know of a better way that it could be implemented without sacrificing the other design goals of D (including an easy to implement compiler), I love to hear it. Since the time that I only knew fortran 77 and Commodore basic, I've want MI functionality. I just didn't know what it was called until I learn C++.I was thinking about this this morning... you *do* lose a nice feature without MI. The real reason that I think that's the case is because it's a bitch to get it right. There are so may cases of conflicting functions... how do you resolve them and know which function to call? Suppose classes A and B both define foo(). C inherits from both A and B, which one do you inherit? What if foo() in A and B were redefined from a common ancestor, Z? What if one of them is final? There's just too much to think about. Here's my thought: What about allowing MI, as long as there are *no* conflicts? None. Whatsoever. If there are, it's an error. That allows the useful part of MI without getting into the mess. Now, if anyone has a good way of resolving conflicts (I hear Eiffel is good at that) I think we'd all be willing to hear it. But disallowing conflicts shouldn't affect the compiler too much (it just fills in the vtable it was going to leave blank), and it gives ua a nice feature to play with. Comments on that? Eric
Oct 24 2001
"Sean L. Palmer" wrote:I've got two words for you. Virtual and inheritance.[ ... snip ... ] AMEN! Jan
Oct 24 2001
On Wed, 24 Oct 2001, Sean L. Palmer wrote:enables both these things, but they're both unnecessary. MI is appealing conceptually, until you've had to throw away a few spaghetti projects because you couldn't disentangle them.If you really want to know an elegant MI design, please read this tutorial page: http://www.eiffel.com/doc/online/eiffel50/intro/language/tutorial-10.html#pgfId-515052 It's not a very long page, please do take a few minutes to read, particularly about the keywords :'rename', 'export', 'undefine', 'redefine' and 'select'. And then go back to your questions and see if you're convinced (pay close attention to the section: "Repeated inheritance and selection"). The answer has already been there for years, only if people care to read. BTW, the data persistence machinism of Eiffel is also something I'd like to see in D: 'store' and 'retrieve' the whole object structure starting from a root object to either a disk file or a network connection (by taking into account of reference sharing and circlarity). Even better, the deep_clone gives you a deep copy of the whole object structure in the memory. Hi, Walter, you didn't give much detail about the data persistence machinism of D online. Have you got any plan about it yet? A final question will be, when will the compiler be ready for download? :-)
Oct 26 2001
Say you have this situation: class A {} class B : A {} class C : A {} class D : B, C {} Now how many instances of A are in D? Two? Or one... but which one, the one from B or the one from C? What if both B and C try to use the same A? Will it behave ok, or will it be a bug? Can you tell the compiler which one to keep, or to merge the two, or to keep both and have duplicate, possibly conflicting data? How do clients figure out how to get a pointer to the A part of a D?I *sincerely* urge you to read the following page to find an clean (and fully programmer-controllable) solution for your questions: http://www.eiffel.com/doc/online/eiffel50/intro/language/tutorial-10.htm l#pgfId-515052See above, please read : http://www.eiffel.com/doc/online/eiffel50/intro/language/tutorial-10.htm l#pgfId-515052Suppose classes A and B both define foo(). C inherits from both A and B, which one do you inherit? What if foo() in A and B were redefined from a common ancestor, Z? What if one of them is final? There's just too much to think about.There is runtime overhead for the solution C++ came up with to allow one to specify that the compiler should merge the A's together. MI really just opens up a whole can of worms that is just better left closed. I've argued the opposite point too, years ago, but lately I reallyIt's only because C++'s ugly implementation of MI. And because C++ is such a popular language (unfortunately), most people's way of thinking is brain-washing by C++. There are life beyond C++, if you are serious about MI, PLEASE READ: http://www.eiffel.com/doc/online/eiffel50/intro/language/tutorial-10.htm l#pgfId-515052 And check again if your above questions are solved cleanly. P.S. If you do not know Eiffel before, the 'anchored type' is also very interesting, something one can only dreamed of in a C++/Java controlled world.
Oct 27 2001
Diamond MI: A / \ / \ B C \ / \ / D Eiffel's solution: rename: change the name of a method export: change the accessibility of a method undefine: keep the method name and signature, but undefine the method body (or in C++'s term, change it to an abstract pure virtual func) redefine: (in C++: virtual, because Eiffel won't implicitly override) select: select one of the repeatedly inherited methods. default behavior: merged (shared) So in Eiffel you can even *safely* write: class B inherit A ... A ... A ... end Something you won't able to do in C++. P.S. (This is yqz comlab.ox.ac.uk, I'm using my friend's E-mail account.)
Oct 27 2001
Frankly, I don't think your idea will make it in, at least not any time soon. The decision seems to have already been made. I am curious what the `default` behavior actually does? Merge sounds a bit odd. To be honest, it sounds like this could make call forwarding/delegation very easy. It's as if the parent classes are almost member data, the apropriate methods are defined to forward as specified and the class signature is updated. It sounds like it could be straight forward enough. I still thinkk it won't happen in this language. There is a bit of an anti-MI support group going here. I'm afraid I could not read the page you gave. One message had bad URLs and the other message had a reference to a page that does not render well in my browser. It's kind of funny actually. By the time you reach the bottom of the page the text is so large that only two lines will fit on the screen, and the word "Engineering," takes up the entire width of the screen. Dan xiaochuang ling wrote:Diamond MI: A / \ / \ B C \ / \ / D Eiffel's solution: rename: change the name of a method export: change the accessibility of a method undefine: keep the method name and signature, but undefine the method body (or in C++'s term, change it to an abstract pure virtual func) redefine: (in C++: virtual, because Eiffel won't implicitly override) select: select one of the repeatedly inherited methods. default behavior: merged (shared) So in Eiffel you can even *safely* write: class B inherit A ... A ... A ... end Something you won't able to do in C++. P.S. (This is yqz comlab.ox.ac.uk, I'm using my friend's E-mail account.)
Oct 27 2001
I'm afraid I could not read the page you gave.First go to : http://www.eiffel.com/doc/online/eiffel50/intro/language/tutorial-00.html Then click on Section 9.
Oct 27 2001
xiaochuang ling wrote:Same problem. I must have an out of date version of netscape. DanI'm afraid I could not read the page you gave.First go to : http://www.eiffel.com/doc/online/eiffel50/intro/language/tutorial-00.html Then click on Section 9.
Oct 27 2001
Same problem. I must have an out of date version of netscape.Even with the latest Netscape, you may still have problem :-) Many web-pages these days only *support* (I mean it) M$'s IE. On the other hand, Netscape is quite buggy. Maybe you can try opera, if you don't like the fatty IE. http://www.opera.com/ It's small, fast, up-to-date, FREE; and runs on both Win32 and Linux. (Sorry, this is off-topic on this D-list.)
Oct 27 2001