Path: utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!wuarchive!julius.cs.uiuc.edu!apple!vsi1!zorch!xanthian From: xanthian@zorch.SF-Bay.ORG (Kent Paul Dolan) Newsgroups: comp.std.c++ Subject: Re: Packing, Ordering, and Rearranging Message-ID: <1990Oct3.061708.10391@zorch.SF-Bay.ORG> Date: 3 Oct 90 06:17:08 GMT References: <1990Oct1.074231.8639@zorch.SF-Bay.ORG> <57892@microsoft.UUCP> <57898@microsoft.UUCP> Organization: SF-Bay Public-Access Unix Lines: 299 jimad@microsoft.UUCP (Jim ADCOCK) writes: >I have to admit I'm becoming very discouraged by the amount of commentary >this subject is generating, without any corresponding understanding of >the issues as applied to object oriented programming. No more than I am to see you return to a position passed by two weeks ago as inadequate to the needs of the user community, with no progress made whatever from opinions stated at that time. Let's establish a few ground rules: 1) Compilers are not written for the convenience of compiler writers, but of compiler users and users of compiled code. Therefore, promoting user inconvenience in favor of compiler writer convenience is a Bad Thing. 2) Tremendous as the productivity gains can be from using object oriented programming languages, they are at bottom just notational conveniences for ordinary imperative languages. In particular, no new computations become feasible by using OOPLs, though the chance of implementing the old ones correctly or cost effectively may improve. In particular, there is a direct translation of C++ into C, which is merely a change of notation. The price paid for using a new notation should not be the loss of ability to do some common programming tasks, compared to the older notation. 3) The purpose of any standard, and in particular a language standard, is to standardize existing practice, for purposes of making things adhering to the standard more widely and conveniently useable, in particular for programming languages, the code and the programmers trained in its use. Now let's see if some progress is possible. > I don't believe any compiler vendor is going to want to reduce the > amount of capability their C compilers have traditionally provided > for 'bit-twiddling'. And, whether standardized or not, past practice has been that complete, bit by bit control of structure layouts was always made available to the programmer, albeit not portably so. > The real issue is what methods shall compilers writers be allowed > to use to implement inheritence. This viewpoint is part of the problem in coming to some resolution in this discussion. The convenience of compiler writers should not be an issue. Whether something is possible at all, or only possible with an NP complete computation, is admissible as an argument, but not the compiler writer's mere convenience, where that is gained at the expense of the compiler user. > This cannot have been an issue in the past, because C did not have > inheritence. Beside the point. The same capabilities provided to extend structures by inheritence existed and were widely used and known, when structures were embedded in other structures. The experience of that widely used programming paradigm is completely applicable to the current question. > Use a C structure, don't use inheritence, and chances are about > 99% that your C++ compiler will give you the same layout as your C > compiler. Given that C compiler implementors all tended to lay out structure elements so that they didn't cross boundaries of elements their size laid out in an array beginning at address zero, and left padding between them to assure this, and didn't arbitrarily rearrange structure fields to achieve more efficient packing, and that this habit is reenforced in the C++ implementors, probably true, but note _all_ the conditions. > But, given that a C++ compiler needs to implement inheritence, how > shall vendors be allowed to do so? The first choice would be that they follow the model of existing practice in C, which is to embed the "parent" structure as the first element of the "child" structure. See for example the very pretty general link list structure used for the Commodore Amiga windowing operating system. _Any_ choice should be evaluated to see whether it has a high cost that would preclude the general use of inheritance, one of the great design benefits of an OOPL. Not to keep the reader in suspense, loss of control of structure layout by the programmer/user of the compiler is such a high cost. > Should C++ compiler vendors all be forced to follow the cfront > model? Never having looked at it, I haven't a clue; since I only care about the part that affects me on the outside as a programmer designing code, I care much less about the method or model, than about the final result. > Or should vendors choose object models that maximize efficiency > for their target machines? This choice is not even expressed along the relevant axes. The question which needs consideration is, should compiler writers/vendors choose to wrest control of structure layout, in the case of structures built piecemeal by inheritance, from the programmer? Again, it needs emphasis, the same structure _functionality_ can be built in a non-OOPL, without inheritance. That it is built by the mechanisms of inheritance is a convenience of notation, but not an essential characteristic of the structure, so the question of the structure's utility to the programmer should be considered _independent_ of the notational mechanism used to build the structure. (Given that the programmer retains complete control of the structure layout, the same _structure_ can also be built in a non-OOPL.) If the programmer, by deliberate coding choice, expresses no need to control the layout of a particular structure exactly, which may be the majority case, then the compiler writer will, simply to meet competition from other vendors, do the most efficient implementable optimizing layout possible, but this cannot be allowed to become the only case, to the exclusion of the programmer's _preeminent_ right to demand complete control in order to accomplish the programming task at hand _when_ _needed_. > I, for one, believe there is a need to allow multiple object > models. This only makes sense if it is not allowed to diminish the utility of the notational convenience which is inheritance. If it does, then we have put the wrong group's interests foremost. > Differing object models can allow significant trade offs between > speed and space. Wonderful, but if you give me fast, compact code that prevents me from doing _my_ job, where is the gain? Your code may look wonderful in the benchmarks, and sell well in the market place, but when word gets out that it is unusable, what have you profited by denying the programmer control of the code's results? > Differing object models may be necessary to interface to other > OOPLs, or systems. Interfacing at the data level, what more than exact layout control could you offer, and how could you possibly expect to succeed at this task if you don't offer at least that much? > Newer object models can provide overall speed enhancements. If your insistance on control of structure layout, to the preclusion of my controlling it when I need that control, prevents me from doing my job, or from using inheritance, and gaining its productivity benefits, how has your faster compiled code helped me? Code still costs more to write than it does to run in all but the most extreme cases, and if you force me back to more primitive methods and increase the cost of my code implementation, of what use to me is it when it runs fast but is delivered too late for its intended task or market window of opportunity? > Therefore, I believe the issues are different in the face of > inheritence as opposed to a language without inheritence. As I hope I have successfully demonstrated, this belief is false. The premier criterion _must_ be, can the programmer get done the job s/he needs to do with the tool you have provided. If you have impeded that task, all the speed and code size brags in the world won't repair the damage. > Please don't just keep dragging out historical C examples of how > you like to place bits. I must, until you finally understand the point. The fact that you find history's lessons inconvenient for your arguments on certain questions doesn't make that history any less valid in deciding those questions. I've been programming a _long_ time; many of those examples predate the existance of C. Until you understand the point that this kind of programming is a large part of what the C++ language's audience of programmers will be doing for the lifetime of the language, these historical examples will keep being brought up to avoid the old "those who refuse to learn from history..." problems. Programming's past is also part of its future. New programming tasks will arise as time proceeds, but all those old ones keep coming back in new suits of clothes, and the retreads outnumber the new tasks in day to day programming work. > That's not the issue. You'll still be able to do that. But if I cannot do that with the productivity gains of the new programming model provided by OOPL, but have to revert to the methods of C, then I lose productivity, portability, reuse, and the other benefits of OOP. Also, now with your proposed paradigm, I have to keep two programming models in mind, keep track of when one or the other is appropriate, and in general will be led to make a whole new class of programming mistakes by the added complexity this dual model of programming structures would cause. > The question is, what should language users be allowed to do, and > not do, via inheritence, and what should compiler implementors be > allowed to do, and not do, regards inheritence? Completely true. My answers: Language users should be allowed to do, via inheritance, at least those things which were possible with the pre-OOPL methods of embedding structures that were the predecessors of, and model for, inheritance. This explicitly includes exact structure layout control when needed. Compiler implementors should be allowed to do whatever cute tricks they can think up to gain speed and compactness so long as those don't degrade the utility of inheritance compared to the methods it replaces. End of direct responses. Note that there are really several more questions here: 1) Do I know how the compiler will lay out my structures? 2) Can I control that structure layout at all? 3) Can I do it in portable code? 4) Does that portable code produce portable structures? (I admit this question is a strange one, but see below.) 5) Can I do it for the full range of notational conveniences that an OOPL provides, and enjoy the productivity gains that implies? 6) Can I make use of optimizations provided by the compiler writer when I don't need the structure layout control those optimizations would prevent? In terms of a standard, this leads to these further questions. 1) Does the standard mandate that the compiler's structure layout methods will be documented exactly for each implementation, so that I can know what layout the code produces by inspecting the code and reading the implementation documentation? 2) Does the standard mandate that there will be a way in a C++ compiler to control the layout of structures, so that I can read the implementation documentation expecting to find it? 3) Does the standard mandate that there will be an implementation independent method of controlling structure layout, where the same code leads to the same layout, bit for bit? 4) Does the standard mandate what "bit for bit" means into the teeth of byte order and other machine inconsistencies? 5) Does the standard extend that layout control consistently across all the ways the language has to define a structure, or does it treat such layout control as an unusual case, and isolate it to only the more primitive structure definition methods? 6) Does the standard mandate a #pragma, "exact" keyword, compiler flag, or similar mechanism to yield control of structure layout to the programmer (or yield it to the compiler's layout optimization, depending on which is the default), or does it at least mandate that some such, implementation dependent, method must exist? It is not a given that we can agree to answer all, or any, of these questions "yes", or even agree to answer them at all, but I think it should be a given that the results of the answers or lack thereof will have a large impact on the success and lifetime of the language whose standardization is being discussed here. I hope it can also become a given that the utility of the language to the programmer, not to the compiler writer, should be the paramount criterion for deciding these questions, and that functionality and programmer productivity should preceed speed or compactness of compiled code in measuring that utility. Note that, with history for a guide, we can say with some degree of confidence that each successful C++ compiler implementation _will_ provide _some_ way to control structure layout exactly, since successful past compilers have consistently, though non-portably, done so. The question then reduces to one of whether we (you) choose to capture and mandate that existing practice in this standard, with the gains implied by _making_ this practice standard rather than implementation dependent. If this choice is made in the affirmative, then the next question is how much control of implementations the standard will take on behalf of the programmer/user, with respect to the question of exact structure layout control. [No sense trying to execute the "then" portion until the "if" portion is satisfied, so I'll stop here.] Kent, the man from xanth. -- Whew! ;-)