Jump to page: 1 2
Thread overview
Templates
Aug 18, 2001
Geoff
Aug 22, 2001
Glen Dayton
Aug 22, 2001
Bradeeoh
Aug 22, 2001
Glen Dayton
Aug 22, 2001
kaffiene
Aug 24, 2001
Dan Hursh
Aug 24, 2001
Walter
Aug 25, 2001
Dan Hursh
Aug 26, 2001
Walter
Aug 24, 2001
Angus Graham
Aug 24, 2001
Charles Hixson
Aug 25, 2001
Dan Hursh
Aug 28, 2001
Glen Dayton
Aug 28, 2001
Kent Sandvik
Aug 29, 2001
Dan Hursh
August 18, 2001
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






August 22, 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.


August 22, 2001
> 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.

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



August 22, 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".


August 22, 2001
> 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?

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 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 think that iostreams is an argument for Multiple inheritence then I think you're mad :-)

Peter.


August 24, 2001
kaffiene wrote:
> 
> > 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?
> 
> 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 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 think that iostreams is an argument for Multiple inheritence then I think you're mad :-)
> 
> Peter.

	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.

Dan
August 24, 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


August 24, 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.


August 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.
> 
> Dan
> 
The 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.

August 25, 2001
Walter wrote:
> 
> 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

	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.

Dan
« First   ‹ Prev
1 2