johnson@p.cs.uiuc.edu (11/15/88)
bs@alice.UUCP (Bjarne Stroustrup) answered coggins@retina.cs.unc.edu (Dr. James Coggins) with >Alternatively we could use the trick of never allocating class objects on >the stack. This is the strategy of Simula and most of its decendents. >The snag is that if we did that we would incur an overhead of two memory >management operations per function call and the cost of indirecting every >access to a class object. Measurements on Simula indicates that this cost >is at least a factor of 2 in run-time. Most of Simula's decendents pay >an even higher price. Accepting this overhead would imply giving up large >application areas to C, assembler, and Fortran. C++ was specifically designed >to preserve efficiency in this area. The apparant cost is recompilation time. I don't believe this. The reason is that the mature C++ systems I have seen allocate very few "class objects" (why aren't these just "objects"?) on the stack. Almost all are allocated dynamically. Procedure calling takes a fairly small percentage of time, especially when low-level functions are in-lined, so the factor of 2 seems way out of line. The cost of indirect access to these objects is repaid by the elimination of copying them later. > > 2. Smalltalk-like languages are better tools for developing small > > programs because of their massive built-in class libraries and their > > more flexible (later, dynamic) binding which allows polymorphic types. >Again I must disagree. Of course you can throw a small Smalltalk program >together to do many things that would be painful to build from scratch in >C++. However, the massive libraries and the wonderful program development >environment of Smalltalk is not something that C++ lacks because of some >inherent defect. Rather, Smalltalk is about 10 years older than C++ and >have had something like 100 times more effort and resources lavished on >its environment and libraries. I understood Jim Coggins to be saying that he thought that C++ DID have an inherent defect that prevented the large class libraries from being created. I don't really understand what it is about C++ that he thinks causes this, nor am I convinced that C++ has any fatal errors in this regard, but that was his claim. My experience is that Smalltalk is better for prototyping a design, but that once it is finished it doesn't matter that much which language you use. The Smalltalk's that are available now have class libraries that are little changed from what was available in 1982. Thus, it isn't fair to say that Smalltalk is 10 years older than C++. My understanding is that there were only a dozen or so people at Xerox PARC who worked on the Smalltalk programming environment directly (other people were just users). When you count all the people in universities who are using C++, the number of man-years invested in C++ can't possibly be an order of magnitude less than for Smalltalk, and in a year it will be an order of magnitude more. Everywhere I go people are switching to C++, and there are groups of more than a hundred people using C++. There is nothing at all like this for Smalltalk. However, it will take more than a year or two for the C++ programming environment to surpass that of Smalltalk. The reason that Smalltalk programming environments are so good is the same as why Lisp programming environments are so good. Programmers can access contexts and classes from inside Smalltalk so they can easily write debuggers and browsers. A similar system for C++ will require a lot of interaction with the operating system, which will be more complicated and less portable. Thus, making a nice programming environment for C++ is a harder job than making one for Smalltalk, so it will take longer. >There is absolutely no basis for this conjecture and the absense of really >large projects successfully developed and supported in a Smalltalk-like >language is a contraindication. After 16 years of Smalltalk variants and >offshoots we should not be conjecturing on this point. Smalltalk has a >string of spectacular successes to its credit, but as far as I'm aware >large scale systems development isn't among them. Nor was it mentioned >among the things Smalltalk was supposed to be especially good at. I suppose that it depends on what you mean by "large". Smalltalk itself is pretty large. The Analyst is twice as large as Smalltalk. There is a VLSI design system at Tektronix that takes 12 or 16 megabytes (I forget which). I doubt if there have been many C++ systems of this size yet. Smalltalk certainly has some faults when it comes to building large systems, primarily in its support for mulitperson projects, but I think that Dr. Coggins was speaking of "Smalltalk-like" languages (whatever that means) and not Smalltalk itself. I am a great fan of type systems, primarily because I am a fan of good optimizing compilers. The reason that Smalltalk is slow is primarily because it doesn't have an optimizing compiler. Indirection, method-lookup, garbage collection, etc. are all just excuses. Of course, C++ can be efficient without a great optimizing compiler, though a good compiler certainly helps. Type systems are also important in ensuring that components are used correctly. This is especially important when components are used by one group and implemented by another. Type information also makes it much easier to read code. O-o programming increases code reading, so this is important. My type system for Smalltalk is much more flexible than the one for C++. I am curious about Dr. Coggins's explanation of why C++ is not as good for reuse, and wonder how types fit in to it. Ralph Johnson
johnson@p.cs.uiuc.edu (11/19/88)
Claim: (by some unknown person) dynamic binding at run time allowed architecture and implementation to be more independent of each other in practice, therefore the Smalltalk model would be better for large-system development than the Simula model. I agree with the first part of the statement, but C++ provides dynamic binding at run time, so the last half is a non sequitur. >If you prototype using Smalltalk, you adopt the Smalltalk object hierarchy >as your architectural tools/metaphors/thought patterns. You also adopt >the underlying implementations, but they can be thrown out or redone >later. By adopting the Smalltalk environment, you might be >starting off your architectural design effort by putting on a >straitjacket and blindfold. Anything works for small projects. For >large projects the fit of mental models, architecture, and language >abstractions needs to be tighter in order to manage and control the >project. I believe that this fit can be made tighter by designing >abstractions (classes) to fit the project, not twisting the mental >model to fit a predefined hierarchy. This is the '80's version of the >top-down heuristic: > Let the implementation conform to the conception. There seem to be several misunderstandings of Smalltalk here. Smalltalk certainly does not force anyone to use existing classes. People use them because they are well designed. People use classes for control structures, arithmetic, data structures (collections), and user interface design. There really aren't many application specific classes. Any large project will require the creation of many new classes, i.e. you will have to invent your own abstractions and implement them. Most of these classes are universally needed and well done. The main exceptions are the graphics and user interface classes, which were very well designed for 1980, but are showing their age. However, people don't seem to see much need in redesigning the collection classes. It seems to me that you are arguing against reuse. I find that hard to believe. It is very hard to write reusable code, and trying to reuse code that is not reusable is no fun. However, it is possible for code to be reusable, and Smalltalk is an example. Smalltalk programmers reuse code because that is the easiest way to develop a high-quality product. In my opinion, if you aren't interested in reuse then you shouldn't bother with object-oriented programming. However, I'll assume that are you interested in reuse. As a project grows, class hierarchies get extended. This usually results in bad class hierarchies, so eventually they get reorganized. One could claim that you should just have designed them right to begin with, but hind-sight is always so wonderful. The problem is how to get hind-sight, and the solution is to go build something (wrong). I claim that no good designer is going to find a class hierarchy a straight-jacket, because if it is not working then it will be changed. There are several situations where reuse can cause problems. One is where you program instead of thinking. Thinking is always a good idea, and I push prototyping as an aid to thinking, not as a replacement to it. Another is where you start with a bad package and so have to spend a lot of time fixing it. If there is a better package available, this is a complete waste of time. However, if you are using the only one available then reading somebody else's code prevents you from learning by an even harder way. (I am assuming that the writer of the package that you are using is at least as good a designer as you are, and that the problems with the package are due to narrowness of vision, and not incompetance.) Although prototyping without thinking can cause problems, thinking without prototyping is more common and also causes problems. I have seen people debate for weeks about some point that could be solved in a couple of days by experimentation. It is a lot easier to debate about an algorithm once it is written down, at least people are arguing about the same thing. There should be much, much, much more reuse in software systems. We don't keep inventing new abstractions for arithmetic, why should we be doing it for everything else? It is clear that it takes a long time to come up with good abstractions, so new areas, like user interface design, go through a lot of fermet until they mature. However, eventually we figure out what we are doing and then we can quit throwing out our old software can can just reuse it for awhile. There are lots of areas of CS that are well enough understood that we should be able to standardize them. This includes many areas in operating systems (scheduling, file systems), areas in business (general ledger, receivables, payables), and a lot of graphics. Then people can write books about these abstractions and we can just use them. In a couple of years C++ will have just as large a class library as Smalltalk, maybe larger. Lots of companies are already developing their own. Nobody will force you to use them, but the high-quality libraries will have lots of users. >>My type system for Smalltalk is much more flexible than the one for C++. >>I am curious about Dr. Coggins's explanation of why C++ is not as good >>for reuse, and wonder how types fit in to it. >The question is whether the flexibility in the type system afforded by >late dynamic binding is ultimately an advantage (by virtue of its >additional support for abstracting architectures independent of >implementations) or ultimately a disadvantage (by delaying detection >of errors and in fact not detecting as errors some things that in fact >are errors). One of the purpose of a type system is to detect errors at compile-time. A type system for an object-oriented language, for example, should prevent any "message not understood" errors at run-time. I don't see why late binding itself prevents the detection of errors. As I said earlier, C++ virtual functions provide late binding, and the type system for C++ ensures that an object understands the messages sent to it.
johnson@p.cs.uiuc.edu (11/22/88)
Let me make one thing clear: I am a Smalltalk programmer. Smalltalk is my favorite language and I consider C++ definitely inferior. I have been defending C++ (and will continue in this article) so I wanted to make that clear. I think that my comments are reasonably representative of the Smalltalk community. Smalltalk certainly has a more dynamic programming environment than C++, but the language itself is not much more dynamic. If you are trying to send a message to an object that does not understand it then you will get a run-time error. If you want a procedure to work with any object that understands Foo and Fee then you make an abstract class FooFeeable and use multiple inheritance to make every class understand it that might be an argument to that procedure. (In my opinion this is the main reason for multiple inheritance.) Very few Smalltalk programs take advantage of the fact that they can generate code on the fly. Smalltalk programs do sometimes check the class of objects. This is often a sign of poor design, but try defining a general equality procedure without it. This is the way I can see in which C++ is significantly less dynamic than Smalltalk. The major problem with C++ is that it is too much like C, but then this is its major strength, too. As I said before, it is the programing environment of Smalltalk that is more dynamic than that of C++, not the languages themselves. The languages certainly have an impact on the environments. Smalltalk makes it easy to write browsers, debuggers, inspectors, and the like. However, given enough work, it should be possible to do it for C++. I commented... >>Smalltalk certainly does not force anyone to use existing classes. >>People use them because they are well designed. Dr. James Coggins commented... >That's a correct Party Line response that is meaningless in practice. >This is exactly the kind of conventional wisdom that should be >examined more carefully. Each of these classes in the Smalltalk >architecture comes with an implementation bound up with it. Part of >the price you pay for using Smalltalk is the tacit adoption of those >implementations along with the nice architecture. The important feature of the Collection hierarchy is the protocol, i.e. do:, select:, collect:, add:, etc. I usually start off a program using OrderedCollection, Dictionary or Set. Once I figure out what I am doing I often discover that these are too inefficient. Then I will write a specialized class to implement the exact kind of Collection that I need. The advantage of using a standard protocol is that 1) readers of my program will know what the new data structure does without reading the code 2) I don't design an efficient data structure until I know that I need it 3) I might luck out and be able to reuse the specialized class. Most times that I use a Collection its efficiency is unimportant, so I never have to reconsider what I've done. I said >>I claim that no good designer is going to find a class hierarchy a >>straight-jacket, because if it is not working then it will be changed. Dr. James Coggins said >I am a good designer (only a fair implementer, though), and I found the >Smalltalk hierarchy restricting when I needed to implement large objects >like images and 3-D graphics models. I wasted time trying to fit what >I needed into what Smalltalk provided. What you said was that you found an application where the particular Smalltalk implementations were not what you needed. So build another one! Maybe you were saying that the abstractions provided by Collection were inappropriate for your problem. This is a more fundamental design error, and one that is not the fault of Collection. In other words, you should have realized that you needed a different abstraction. Of course, hind-sight is 20/20, the problem is how to get hind-sight. I said >>There should be much, much, much more reuse in software systems. We don't >>keep inventing new abstractions for arithmetic, why should we be doing it >>for everything else? Dr. James Coggins said >Because there is no "implementation" for arithmetic, of course! >Computer stuff is bound to implementations requiring engineering >decisions concerning tradeoffs of time/space, compilation >effort/run-time support effort, etc. Note that I said "abstractions" not code. The abstractions are much more important than the code. If you made a mistake in the implementation of a class then you can just write another one. If you designed the interface wrong then you will not only have to reimplement the class but every client of the class. Every language that I have used gives the same definition for + on integers. I want the same thing to be true of sets.
coggins@retina.cs.unc.edu (Dr. James Coggins) (11/23/88)
In article <77300017@p.cs.uiuc.edu> johnson@p.cs.uiuc.edu writes: > >As I said before, it is the programing environment of Smalltalk that is >more dynamic than that of C++, not the languages themselves. Certainly this is true, but the language differences are still significant. Errors Smalltalk picks up at run-time are compile-time errors in C++. Bjarne Stroustrup recently argued in this newsgroup that early detection of errors is a principal advantage of C++ over Smalltalk for large-scale real software development. [I'm deleting a good description of how to do rapid prototyping in Smalltalk.] >What you said was that you found an application where the particular >Smalltalk implementations were not what you needed. So build another one! I did. In C++. Where the nature of the implementation was under my control. Where I could fit the implementation to the abstraction instead of the other way around. >Maybe you were saying that the abstractions provided by Collection were >inappropriate for your problem. This is a more fundamental design error, >and one that is not the fault of Collection. I saw very quickly that Collection was not what I wanted and neither was anything else in the Smalltalk world. (I said I'm a GOOD designer!) It was disappointing to spend the time to learn the Smalltalk model and find it inappropriate. > >johnson said >There should be much, much, much more reuse in software systems. We don't >keep inventing new abstractions for arithmetic, why should we be doing it >for everything else? > >Dr. James Coggins said (this is amended somewhat from the original) >Because there is no "implementation" for arithmetic, of course! >As soon as abstractions are made computer-usable, they are bound to >implementations requiring engineering decisions concerning >tradeoffs of time/space, compilation effort/run-time support effort, >etc. We have no mechanism available for specifying the nature of abstractions that is not bound up with some implementation. For rapid prototyping, something like Smalltalk provides default implementations, and you correctly described how those should be modified in response to real needs as a project develops. But at some point you need to build the Product, not a prototype of it. From the prototype you might know how you would like the user interface to work, what critical algorithms are required, and you might know something about performance problems. But if you have expressed the prototype in a system of Smalltalk classes that is not a good fit between the essential abstractions and implementations thereof, then the prototype tells you less about the Product than you thought. This all boils down to something I wrote once called "Object-Oriented Design Considered Harmful". The most negative effect of OOD is that it encourages bottom-up design. Top-down design remains the best approach (though bottom-up realization makes lots of sense a lot of the time). Huge class libraries might save some coding and typing time, but we haven't even begun to fabricate the "silver bullet" until we find an effective mechanism for divorcing the architecture of a system from its implementation. Then we might be able to adopt and reuse architectures like large class hierarchies conforming to different conceptions of diverse problem domains while also interchanging implementations. Then maybe the "software IC market" will be less of a pipe dream and we will really be able to "Let the implementation conform to the conception." --------------------------------------------------------------------- Dr. James M. Coggins coggins@cs.unc.edu Computer Science Department UNC-Chapel Hill Member of the Dreamer Fithp Chapel Hill, NC 27514-3175 ---------------------------------------------------------------------
djk@murtoa (David Keegle) (11/23/88)
From article <77300017@p.cs.uiuc.edu>, by johnson@p.cs.uiuc.edu: ] I said ]>>There should be much, much, much more reuse in software systems. We don't ]>>keep inventing new abstractions for arithmetic, why should we be doing it ]>>for everything else? Hear, hear! ] Dr. James Coggins said ]>Because there is no "implementation" for arithmetic, of course! ]>Computer stuff is bound to implementations requiring engineering ]>decisions concerning tradeoffs of time/space, compilation ]>effort/run-time support effort, etc. ] ] Note that I said "abstractions" not code. The abstractions are much ] more important than the code. If you made a mistake in the implementation ] of a class then you can just write another one. If you designed the ] interface wrong then you will not only have to reimplement the class ] but every client of the class. Every language that I have used gives ] the same definition for + on integers. I want the same thing to be ] true of sets. OK, what is ``maxint + maxint'' (your syntax may vary etc.) then? :-) ;-) David Keegel (djk@munnari.oz) "A tautology is something which is tautologous."