D - Templates
- Geoff (41/41) Aug 17 2001 Walter,
- Glen Dayton (35/35) Aug 21 2001 We've mixed two different topics.
- Bradeeoh (36/39) Aug 21 2001 You're right, you can't create instances of Interfaces. But, indeed, yo...
- Glen Dayton (35/35) Aug 22 2001 Of course your arguments apply if you have control of the hierarchy; and...
- kaffiene (10/23) Aug 22 2001 One of the good things about Java is having to be explicit about what is...
- Dan Hursh (15/44) Aug 23 2001 I do think the truck and boat example was a good reason though. If
- Walter (20/26) Aug 24 2001 Your reasoning has merit. The counterargument (and I've discussed this a...
- Dan Hursh (66/97) Aug 25 2001 I can accept the argument that multiple inheritance the C++ way gets
- Walter (6/20) Aug 25 2001 Unfortunately, the reality is I can't implement a lot of great features.
- Angus Graham (8/14) Aug 24 2001 I don't think this is such a bad argument.
- Charles Hixson (16/25) Aug 24 2001 The problem is, there's a limited amount of developer time/energy. So
- Dan Hursh (12/41) Aug 25 2001 True. I got whiny. It was past my bed time. I can agree with
- Glen Dayton (18/18) Aug 28 2001 When everything inherits from a common Object class, the argument for
- Kent Sandvik (16/21) Aug 28 2001 inheritance
- Dan Hursh (19/40) Aug 28 2001 There are costs for this. To get template functionality from a base
Walter, I agree with you that multiple inheritance is of dubious usefulness. Smalltalk and Java do just fine without it. I encounter multiple inheritance a lot in C++ code, but it never makes the code more understandable than the equivalent written with single inheritance. It's important to remember that high level languages are for people to read, not machines, else we'd write everything in asm. So if you and I, and a lot of other experienced programmers find designing code and/or reading code designed by others using multiple inheritance gnarly, that's reason enough not to have it. I've written significant amounts of code in C, C++, Smalltalk, Java, Fortran, APL, Pascal, Cobol, and various macro assemblers. I've read about others, including Ada and Eifel. They all have problems. C and Smalltalk are probably my favorites. C for its simplicity and power. Smalltalk for its OO. Over the course of a 3 year, ten person C++ project, I have grown to detest C++. If C++ was supposed to bring the benefits of OO to C, it has failed utterly. Maybe D can do it right. I like most of what you have in the spec. Please see if you can find a way to leave templates out. Yes you need to have generic code, but there has to be a better way. Most of the people who have said they need templates, really just mean that they need generic code. Smalltalk, the original OO language, is still the language that allows generic code to be written most easily. Of course big Smalltalk programs have a nasty habit of falling over at runtime with a 'message not understood by...' pop-up because an object passed to a generic method doesn't implement a required interface. Type checking can save your butt. It seems to me that you could have the simplicity of Smalltalk style generic code, if only the compiler could forsee all possible types that can arrive at a method. In Smalltalk you try to make your code more robust by asking incoming parameters for their type info, before you try to access a non-existant member. Of course, then your code isn't completely generic anymore. Interfaces, as in Java, help. Maybe all function parameters should be typeless, but instead define only the interface(s) that each parameter must implement. i.e. foo( a { implements + operator), b { implements iterator, + operator } ); I'm not sure this is making sense, but give it some thought. -Geoff
Aug 17 2001
We've mixed two different topics. Many OO programmers believe multiple inheritance to be of dubious value, but perhaps this is because of the lack of expressiveness in the languages we have been forced to use of late. One of the arguments against multiple inheritance is that in most OO languages a common subclass may always be found, but this leads to over-abstraction and a violation of isolation principles. Simple mathematical analysis using set notation demonstrates the need for multiple inheritance, and the limitations of our current languages. To omit multiple inheritance would gravely harm the utility of the language just because we haven't thought out what is really meant by multiple inheritance. For example, an amphibous truck is both a truck and a boat. Trucks and boats are vehicles. Unfortunately, in C++, the class tree that represents this yields ambiguous definitions: class Vehicle {...} class Truck : Vehicle {...} class Boat : Vehicle {...} class AmphibiousTruck : Boat, Truck; AmphibiousTruck inherits the union of attributes of Boat and Truck, but not all Trucks are AmphibiousTrucks -- so it would not be correct to downcast all references to Trucks to references of AmphibiousTrucks. Never mind C++ introduces arcane "virtual" inheritance to control whether you get 2 sets of Vehicle attributes or just 1. Java interfaces don't help much. An AmphibiousTruck is not merely a Vehicle with a Truck interface and a Boat interface. You can create instances of Boats and Trucks but you can't create instances of interfaces. One solution is that D implement multiple inheritance, but all inheritance is statically "virtual". C++ does virtual inheritance through high overhead vtable pointers. D has enough information in its type library (from not having to use include files) to coalesce multiple references to base classes. I'm sure, though, that this approach has its own shortcomings that I hope many will point out. Template classes also capture the important mathematical concepts of the transformations of sets. They are absolutely essential if you want to get rid of non-type safe macros.
Aug 21 2001
Java interfaces don't help much. An AmphibiousTruck is not merely aVehiclewith a Truck interface and a Boat interface. You can create instances of Boats and Trucks but you can't create instances of interfaces.You're right, you can't create instances of Interfaces. But, indeed, you can refer to objects by the interfaces they implement. For example (using Java notation ) - public class AmphibiousTruck extends Vehicle implements Boat, Truck {} public class foo { private Boat boatTruck = new AmphibiousTruck(); private Truck truckBoat = new AmbhibiousTruck(); } Now, I'm not saying there aren't any cases where you can't do something with interfaces that you CAN do with multiple inheritence. I just don't know any. I cheerfully challenge you to show me one :) BTW - I have never run into that problem, perhaps, because of how I construct my hierarchies of objects. Ie - I would implement these examples more like this - public class Vehicle{} public class Truck extends Vehicle implements Wheeled, CargoCarrier, ManualDriver{} public class Boat extends Vehicle implements Floats, ManualDriver{} public class AmphibiousTruck extends Vehicle implements Wheeled, Floats, CargoCarrier, ManualDriver{} public class AmphibiousHoverTruck extends Vehicle implements Wheeled, Floats, CargoCarrier, ManualDriver, Hovers{} etc. ... .. There's a bazillion ways of doing it. It all depends on the problem. No way is more right or wrong than any other, as long as the philosophy behind the design is consistent throughout the project. Some solutions aren't appropriate for some situations, of course, but I contend that for any multiple inheritence solution that would be considered "appropriate", there's a single inhereitence + interface solution to match that alleviates alot of the multiple inhereitence problems. -Brady
Aug 21 2001
Of course your arguments apply if you have control of the hierarchy; and in fact you've spuriously introduced whole new classes and interfaces to overcome a limitation of the language. My specification said nothing about "Wheeled", "CargoCarrier", and "ManualDriver", and so limits the extensibility of the objects in that it now precludes tracked and semi-tracked carriers. The language should make expression of the solution of the problem clear without having to resort to tricks such as wrapping classes around interfaces so you can get an instance of them. One of the frustrating aspects of Java is having to be conscious of what is an interface and what is not. Until you attempt to create a new instance you don't know. A simple test of whether a language is really extensible and suitable for re-usable software is to see how complicated it is to implement each one of the well-known design patterns, such as factory. So, why are multiple interfaces superior to multiple inheritance? If you consider the _type_ of each attribute of a class as a set, then the class becomes a cartesian product of the types of its attributes. An instance of the class is merely a member of the set of that cartesian product. The methods of a class merely become mappings, which may be, and should be treated identically as attributes. In terms of programming practice for maintenance, we usually hide the attributes, and make the mappings available. In mathematical terms, though, there is no reason to treat them differently. When you start treating methods as members of sets, there is no mathematical difference between interfaces and multiple inheritance. The C++ iostream class is a clear demonstration of when multiple inheritance is useful and elegant. It is possible to use abstract classes and multiple inheritance to simulate interfaces, but because you can't instantiate interfaces, you can't use interfaces to simulate multiple inheritance. (Don't confuse this type of interface with CORBA's instantiable interfaces). In other words -- it was possible to implement iostreams with interfaces, but the code would have been less extensible and more complicated. If you really want D to be compiled-to-native-code Java, it already exists (look at Apogee Software's offerings). If D is really to be the successor to C++, it really needs to drop Java concepts like "no multiple inheritance".
Aug 22 2001
One of the frustrating aspects of Java is having to be conscious of whatisan interface and what is not. Until you attempt to create a new instance you don't know. A simple test of whether a language is really extensible and suitable for re-usable software is to see how complicated it is to implement each one of the well-known design patterns, such as factory.So,why are multiple interfaces superior to multiple inheritance?One of the good things about Java is having to be explicit about what is an interface and what isn't. It leads to good design rather than the sloppy way it is done implicitly in C++The C++ iostream class is a clear demonstration of when multipleinheritanceis useful and elegant. It is possible to use abstract classes and multiple inheritance to simulate interfaces, but because you can't instantiate interfaces, you can't use interfaces to simulate multiple inheritance. (Don't confuse this type of interface with CORBA's instantiableinterfaces).In other words -- it was possible to implement iostreams with interfaces, but the code would have been less extensible and more complicated.If you think that iostreams is an argument for Multiple inheritence then I think you're mad :-) Peter.
Aug 22 2001
kaffiene wrote:I do think the truck and boat example was a good reason though. If someone already implement a truck and someone else implemented a boat, and I wanted to be able to make some that was both, I can't. Period. The closed I could come would either be to re write the world, or create an object he is one thing (a truck) and has the other (a boat) and access the has-a member when I need to be that type, and even then it isn't as flexible. Single inheritance may be easier to implement, but you are losing something. It's a little concerning how often folks here take the opinion that "Feature X has problems and I never use it anyway, so no body else 'really' needs it." I'm not specificly blaming you, but i've lost track of how many time if seen that reasoning tonight. I'm afraid I'll see it a lot in the 275 I still have to read. DanOne of the frustrating aspects of Java is having to be conscious of whatisan interface and what is not. Until you attempt to create a new instance you don't know. A simple test of whether a language is really extensible and suitable for re-usable software is to see how complicated it is to implement each one of the well-known design patterns, such as factory.So,why are multiple interfaces superior to multiple inheritance?One of the good things about Java is having to be explicit about what is an interface and what isn't. It leads to good design rather than the sloppy way it is done implicitly in C++The C++ iostream class is a clear demonstration of when multipleinheritanceis useful and elegant. It is possible to use abstract classes and multiple inheritance to simulate interfaces, but because you can't instantiate interfaces, you can't use interfaces to simulate multiple inheritance. (Don't confuse this type of interface with CORBA's instantiableinterfaces).In other words -- it was possible to implement iostreams with interfaces, but the code would have been less extensible and more complicated.If you think that iostreams is an argument for Multiple inheritence then I think you're mad :-) Peter.
Aug 23 2001
Dan Hursh wrote in message <3B85F62A.3C3D8591 infonet.isl.net>...Single inheritance may be easier to implement, but you are losing something. It's a little concerning how often folks here take the opinion that "Feature X has problems and I never use it anyway, so no body else 'really' needs it." I'm not specificly blaming you, but i've lost track of how many time if seen that reasoning tonight. I'm afraid I'll see it a lot in the 275 I still have to read.Your reasoning has merit. The counterargument (and I've discussed this at length with my colleagues) is that C++ gives you a dozen ways and styles to do X. Programmers tend to develop specific styles and do things in certain ways. This leads to one programmer's use of C++ to be radically different than another's, almost to the point where they are different languages. C++ is a huge language, and C++ programmers tend to learn particular "islands" in the language and not be too familiar with the rest of it. Hence one idea behind D is to *reduce* the number of ways X can be accomplished, and reduce the balkanization of programmer expertise. Then, one programmer's coding style will look more like another's, with the intended result that legacy D code will be more maintainable. For example, over the years I've seen dozens of different ways that debug code was inserted into a program, all very different. D has one way - with the debug attribute/statement. C++ has a dozen string classes plus the native C way of doing strings. D has one way of doing strings. I intend to further help this along by writing a D style guide, "The D Way". There's a start on it all ready with the document on how to do error handling: www.digitalmars.com/d/errors.html
Aug 24 2001
Walter wrote:Dan Hursh wrote in message <3B85F62A.3C3D8591 infonet.isl.net>...I can accept the argument that multiple inheritance the C++ way gets ugly easily for reasons X, Y & Z and that we don't to copy it or throw in something just as bad. I just don't like the "I don't use it so no one should" type statements, like the one I was responding to, when I have used the feature often and well. In response to the above, I don't mean to demand multiple inheritance. I do believe it is handy in C++ when done right. It is unusable when done wrong. I just don't see single inheritance w/ interfaces as a full solution. Likewise with the lack arbitrary sized numeric types and operator overloads or matrix math and overloads, and a bunch of other debates going on. I just want to make sure we understand when we are saying X cannot be done. In the case of the message I responded to, we are saying there is no convenient way to reuse the code of two classes to create one that behaves as both. You either re-write the universe (or microcosm) with interface or you try to find a way to kludge with a has-a relationship. I guess I'm also a little scared that a debate will end with "I don't use it ...". I doubt you would end a debate that way and I owe you an apology for acting like you might. Along with what you said, C++ is too big. I hope D does not ever become like C++ in that sense. I like to see all the interest here, but in the end I would rather that D, in it entirety, be something that "feels right" inside one person's head (yours on this case) than to have it be the language that made it though a committee with the least amount of bickering. I had a longer response (like this isn't rambling), but I realized it could be simplified to: - perl v. python (/me is in the perl camp but understands the python camp) - one way to do things can lead to a steep learning curve if when too many features must be understood before you can apply the "One True Way" - a rant/example about Java's library and the problem it has caused at work this way. - too many "One True Way"s to understand - they get misused because the developer didn't pick/notice the better "One True Way". - C++ is the same because of it's library and the language itself - the increment nature of perl is good - you can learn a little bit at a time and still be productive - C had a steeper learning curve, but the shape of the curve resembled perl more than C++ I guess I'll hope D is a good incremental language. And I've also convinced myself that the library can be a very huge source of evil if it forces the user to understand all of it before he can use any of it. (perhaps the library should be a bunch of small, independent, compatible pieces?) I also hope we don't sacrifice the ability to solve reasonable classes of problems just because we don't like how C++ implemented the solution. I've been impressed with how some of the uses of the preprocessor have been dealt with and how some of the operator overloading uses have been dealt with. I trust that generic programming will make it into the language in a form that will make C++ programmer secretly jealous and that it is a matter of finding the better way. I admit that single inheritance w/ interfaces handles a lot more than just single inheritance, but the are still real code reuse issue that this doesn't address. The style guide would probably be a good discussion piece to start from for addressing things. It would be a good thing to look at and then ask "how do I do X". Either we update the guide, we update the language, or we say "you don't". It has to be a lot more productive than my ramblings. I guess I should shut up so you can finish the first pass on compiler and the guide then. DanSingle inheritance may be easier to implement, but you are losing something. It's a little concerning how often folks here take the opinion that "Feature X has problems and I never use it anyway, so no body else 'really' needs it." I'm not specificly blaming you, but i've lost track of how many time if seen that reasoning tonight. I'm afraid I'll see it a lot in the 275 I still have to read.Your reasoning has merit. The counterargument (and I've discussed this at length with my colleagues) is that C++ gives you a dozen ways and styles to do X. Programmers tend to develop specific styles and do things in certain ways. This leads to one programmer's use of C++ to be radically different than another's, almost to the point where they are different languages. C++ is a huge language, and C++ programmers tend to learn particular "islands" in the language and not be too familiar with the rest of it. Hence one idea behind D is to *reduce* the number of ways X can be accomplished, and reduce the balkanization of programmer expertise. Then, one programmer's coding style will look more like another's, with the intended result that legacy D code will be more maintainable. For example, over the years I've seen dozens of different ways that debug code was inserted into a program, all very different. D has one way - with the debug attribute/statement. C++ has a dozen string classes plus the native C way of doing strings. D has one way of doing strings. I intend to further help this along by writing a D style guide, "The D Way". There's a start on it all ready with the document on how to do error handling: www.digitalmars.com/d/errors.html
Aug 25 2001
Dan Hursh wrote in message <3B875392.F1956643 infonet.isl.net>...I guess I'm also a little scared that a debate will end with "I don't use it ...". I doubt you would end a debate that way and I owe you an apology for acting like you might.Unfortunately, the reality is I can't implement a lot of great features. There are just too many.Along with what you said, C++ is too big. I hope D does not ever become like C++ in that sense. I like to see all the interest here, but in the end I would rather that D, in it entirety, be something that "feels right" inside one person's head (yours on this case) than to have it be the language that made it though a committee with the least amount of bickering.I think it feeling right is important.I guess I'll hope D is a good incremental language. And I've also convinced myself that the library can be a very huge source of evil if it forces the user to understand all of it before he can use any of it. (perhaps the library should be a bunch of small, independent, compatible pieces?)Yes, I want to make the library that way. The Java library turns out to be if you use any piece of it, you drag in the whole thing.
Aug 25 2001
"Dan Hursh" <hursh infonet.isl.net> wrote... It's a little concerning how often folks here take the opinion that "Feature X has problems and I never use it anyway, so no body else 'really' needs it." I'm not specificly blaming you, but i've lost track of how many time if seen that reasoning tonight. I'm afraid I'll see it a lot in the 275 I still have to read.I don't think this is such a bad argument. Everything it useful to someone right? So should everything be in then? No, you try balance the yeas with the nays in order to have the best language for the greatest number. I say nay to virtual inheritance because I don't use it and I wish the programs I maintain didn't either. If the majority says yea, well that's just one more thing I have to concern myself with whether I like it or not.
Aug 24 2001
Dan Hursh wrote:... It's a little concerning how often folks here take the opinion that "Feature X has problems and I never use it anyway, so no body else 'really' needs it." I'm not specificly blaming you, but i've lost track of how many time if seen that reasoning tonight. I'm afraid I'll see it a lot in the 275 I still have to read. DanThe problem is, there's a limited amount of developer time/energy. So one must remember K.I.S.S. OTOH, the basic features need to be present that will allow the language to grow over time into the "proper" shape. Were I arguing for what I want, I'd not only argue for multiple inheritance, but for an interpreter as well as a compiler, with linkages between the object code from the compiler and the code executing in the interpreter. That way features that couldn't be totally compiled would be able to have their flexible features managed by the interpreter, while the rest could run at compiled speed. And code that was simple enough could be unzipped from the interpreter, and run stand-alone. But let's be reasonable. Interfaces + delegation can handle almost all of what multiple inheritance can handle. If there are ways to expose the C compatible links, then Python or Ruby can be used for the interpretive layer. etc. If it gets too complex, it won't get done. People argue for what they want, and Walter *decides*. It MUST be that way.
Aug 24 2001
Charles Hixson wrote:Dan Hursh wrote:True. I got whiny. It was past my bed time. I can agree with K.I.S.S. and growing the language. I am afraid of having a library based on the state of the language before it grew. Libraries are sometimes harder to change than languages once they are in use. Of course it will probably be a while until we have a library that sticks. OTOH, I don't buy the "I don't like it ..." argument. Walter is about the only one who can get away with that and from what I can tell that's not his style. I just don't want to give up on finding a good implementation of a good functionality just because someone else doesn't use or like a bad implementation of it. I'm still too young and idealistic for that.... It's a little concerning how often folks here take the opinion that "Feature X has problems and I never use it anyway, so no body else 'really' needs it." I'm not specificly blaming you, but i've lost track of how many time if seen that reasoning tonight. I'm afraid I'll see it a lot in the 275 I still have to read. DanThe problem is, there's a limited amount of developer time/energy. So one must remember K.I.S.S. OTOH, the basic features need to be present that will allow the language to grow over time into the "proper" shape. Were I arguing for what I want, I'd not only argue for multiple inheritance, but for an interpreter as well as a compiler, with linkages between the object code from the compiler and the code executing in the interpreter. That way features that couldn't be totally compiled would be able to have their flexible features managed by the interpreter, while the rest could run at compiled speed. And code that was simple enough could be unzipped from the interpreter, and run stand-alone. But let's be reasonable. Interfaces + delegation can handle almost all of what multiple inheritance can handle. If there are ways to expose the C compatible links, then Python or Ruby can be used for the interpretive layer. etc. If it gets too complex, it won't get done. People argue for what they want, and Walter *decides*. It MUST be that way.
Aug 25 2001
When everything inherits from a common Object class, the argument for templates does grow weaker. C++ needs templates because there is no common ancestor. But when you write generic functions for arguments of class Object, you have explicitly overridden type safety. The original motivation behind templates was to provide a type-safe means of replacing macros. A template captures the concept of operations on classes returning functions and other classes. Templates, though, appear klugey because they use a different syntax than normal functions and methods to achieve their aims. Likewise, when everything inherits from a common class, multiple inheritance appears to be not so necessary. Java tried to eliminate multiple inheritance with interfaces -- but interfaces are nothing more than multiple inheritance with abstract classes. (It looks like a horse, whinnies like a horse, and smells like a horse...) I'll mention my suggestion about multiple inheritance: Implement, but make all inheritance virtual -- eliminate the virtual keyword.
Aug 28 2001
"Glen Dayton" <dayton timesten.com> wrote in message news:9mh7ah$1s7a$1 digitaldaemon.com...Likewise, when everything inherits from a common class, multipleinheritanceappears to be not so necessary. Java tried to eliminate multiple inheritance with interfaces -- but interfaces are nothing more thanmultipleinheritance with abstract classes. (It looks like a horse, whinnies like a horse, and smells like a horse...)The Java interface definition is more of a 'contact', something that the class has to implement. This is one of the best features Java ever implemented -- you could simulate this with an abstract class either directly inherited from, or then with multiple inheritance in C++, but opening up full multiple inheritance is not really needed. The few cases I've seen this tried out in production platforms, such as Pink's mixin classes, it was mostly to support 'contracts' or otherwise provide mixins for building far too complex code. I rather see a nice interface definition than MI, as MI will just cause all kinds of strange pains, namespace issues, which of the named member functions or fields should override, and other similar nastiness. --Kent
Aug 28 2001
Glen Dayton wrote:When everything inherits from a common Object class, the argument for templates does grow weaker. C++ needs templates because there is no common ancestor.There are costs for this. To get template functionality from a base class, you have to use virtual functions (a performance hit) and you have to deal with type error at runtime when template work them out at compile time.But when you write generic functions for arguments of class Object, you have explicitly overridden type safety.But with templates too, you still have to ability to choose type safety.The original motivation behind templates was to provide a type-safe means of replacing macros. A template captures the concept of operations on classes returning functions and other classes....at compile time, like macros.Templates, though, appear klugey because they use a different syntax than normal functions and methods to achieve their aims.Not to me. Template appear kludgy because the syntax for them is ambiguous and has to be backward compatible with C. I don't know if that got compatibility, but it is definitely backward.Likewise, when everything inherits from a common class, multiple inheritance appears to be not so necessary. Java tried to eliminate multiple inheritance with interfaces -- but interfaces are nothing more than multiple inheritance with abstract classes. (It looks like a horse, whinnies like a horse, and smells like a horse...)There are cases of code reuse that single inheritance (even with interfaces) do not handle well. You can say they handle those cases the same way you can say C handles type based dynamic dispatch. You can kludge it in, but you feel dirty in the morning.I'll mention my suggestion about multiple inheritance: Implement, but make all inheritance virtual -- eliminate the virtual keyword.Dan
Aug 28 2001