garya@Solbourne.COM (Gary Aitken) (04/29/89)
Jonathan Shopiro's response to my earlier posting is a help in terms of dereferencing the pointers once they have been given the proper values. However, I don't see any solution (yet) to the problem of getting the proper values in the pointers in the first place. How does one get the address of the virtual function for an object, given a pointer to the object? class A { public: virtual void f() ; } class B : public A { public: void f() ; } typedef void A::MEMF() ; // type for "member function of A" MEMF *fp ; B *bp = new B ; A *objp = (A*) bp ; fp = &objp->f ; // if objp is REALLY a *A, I want &A::f // but if it's REALLY a *B, I want &B::f // again, this works in cfront, with warnings... /* I don't want fp = &A::f because I need the appropriate virtual function to dispatch when the function call is made. */ Or am I missing something here? If I do fp = &A::f and subsequently do a (bp->*fp)() will this somehow go through the virtual table and actually call B::f if bp is REALLY a B* object pointer? (I can't test this right now because our cfront is broken for these constructs right now...) -- Gary Aitken Solbourne Computer Inc. ARPA: garya@Solbourne.COM Longmont, CO UUCP: ...!{boulder,sun}!stan!garya
shopiro@alice.UUCP (Jonathan Shopiro) (04/29/89)
In article <904@garya.Solbourne.COM>, garya@Solbourne.COM (Gary Aitken) writes: > Jonathan Shopiro's response to my earlier posting is a help in terms of > dereferencing the pointers once they have been given the proper values. > However, I don't see any solution (yet) to the problem of getting the > proper values in the pointers in the first place. > > How does one get the address of the virtual function for an object, given > a pointer to the object? > > class A { > public: > virtual void f() ; > } > class B : public A { > public: > void f() ; > } > > typedef void A::MEMF() ; // type for "member function of A" > MEMF *fp ; > B *bp = new B ; > A *objp = (A*) bp ; > > ... > > Or am I missing something here? If I do > fp = &A::f > and subsequently do a > (bp->*fp)() > will this somehow go through the virtual table and actually call B::f if > bp is REALLY a B* object pointer? It REALLY will. I promise. s o r r y a b o u t t h i s s i l l y s t u f f -- Jonathan Shopiro AT&T Bell Laboratories, Warren, NJ 07060-0908 research!shopiro (201) 580-4229
ark@alice.UUCP (Andrew Koenig) (04/29/89)
In article <904@garya.Solbourne.COM>, garya@Solbourne.COM (Gary Aitken) writes: > Or am I missing something here? If I do > fp = &A::f; > and subsequently do a > (bp->*fp)(); > will this somehow go through the virtual table and actually call B::f if > bp is REALLY a B* object pointer? Yes. What you can't do is bind an object and a function pointer into a single value. That is, there's no type you can give x that will let you do this sanely: x = &bp->f; It would be nice, but it is extremely difficult to compile into C because C doesn't let you get your tentacles into its calling sequence portably. -- --Andrew Koenig ark@europa.att.com
mat@mole-end.UUCP (Mark A Terribile) (04/30/89)
> How does one get the address of the virtual function for an object, given > a pointer to the object? > B *bp = new B ; > A *objp = (A*) bp ; > fp = &objp->f ; // if objp is REALLY a *A, I want &A::f > // but if it's REALLY a *B, I want &B::f > I don't want fp = &A::f because I need the appropriate virtual function > to dispatch when the function call is made. ... Or am I missing something > here? If I do fp = &A::f and subsequently do a (bp->*fp)() > will this somehow go through the virtual table and actually call B::f if > bp is REALLY a B* object pointer? ... It sure will. Pointers to virtual members are themselves virtual and go through the virtual tables. How, you ask, is it done? Take my word, you don't want to know. It's ugly. Worse, it imposes a couple of extra instructions of cost on every call-through-a-pointer-to-member-function if the class has *any* virtual members (or perhaps its any virtual members whose argument signatures match; I don't know for sure.) The cost really isn't that great. One of the versions of cfront has a bug that causes it to generate code which triggers error messages or warnings from the C compiler. I don't recall which version it is--it's been a long time since I had to deal with the problem. I had to work around it by creating a friend class whose member functions' only job was to call the appropriate virtual functions in the class hierarchy of interest. -- (This man's opinions are his own.) From mole-end Mark Terribile
jima@hplsla.HP.COM (Jim Adcock) (05/06/89)
> It sure will. Pointers to virtual members are themselves virtual and go > through the virtual tables. How, you ask, is it done? Take my word, you > don't want to know. It's ugly. Worse, it imposes a couple of extra > instructions of cost on every call-through-a-pointer-to-member-function if > the class has *any* virtual members (or perhaps its any virtual members whose > argument signatures match; I don't know for sure.) The cost really isn't > that great. Well, I find the cost somewhat discouraging if all one is trying to do is return a value from an object of uncertain class. For example, try to find an inexpensive way to get a hierarchy of classes to return information about their sizes -- presumably: class baseclass { virtual int size(){return sizeof(baseclass);} }; class derivedclass : baseclass { int size(){return sizeof(derivedclass);} } For these simple get-a-value, put-a-value type virtual access functions one could hope for code that compiles to a simple double indirection: baseclassptr->size(); compiles to: baseclassptr->(vtable+offset_of_size)->a_constant_equal_to_size; or maybe even: baseclassptr->vtable[offset_of_size_constant] The present approach gives code that is about 10X slower than one would hope for in these simple, everyday cases. Again, for OOP to be affordable, these simple, everyday "get" and "put" type functionalities must be handled at minimal cost. Otherwise programmers will violate strict encapsulation, and come up with "hack" solutions.
jss@hector.UUCP (Jerry Schwarz) (05/08/89)
In article <6590114@hplsla.HP.COM> jima@hplsla.HP.COM (Jim Adcock) writes: > >Again, for OOP to be affordable, these simple, everyday "get" and >"put" type functionalities must be handled at minimal cost. >Otherwise programmers will violate strict encapsulation, and come >up with "hack" solutions. I get a frustrated by assertions of this kind. By any standard C++ is "affordable", especially when compared to languages like Smalltalk or Objective C. Note that the item I am replying to was sumbmitted only to comp.lang.c++ so I have to read this as a suggestion that C++ isn't "affortdable". (I suppose I could also read this as an argument for my contention that C++ supports non object oriented styles and therefore derives its affordability by avoiding OOP when neccessary, but the tenor of the item I'm replying to doesn't suggest that reading to me. I apologize if I'm misreading Jim Adcocks note.) In fact, C++ puts you at a low enough level so that (with out violating the type discipline) it is possible to program the operation under discussion (finding the "actual" size of an object) as a simple lookup. class B public const size_t size ; B(int i) : Size(i) ; } ; class D : B { D(...) : B(sizeof(D)) { ... } } ; B* p ; ... p->size ... ; Yes, there is a certain amount of pain involved in programming this explicitly. But recall that the original complaint was that C++ doesn't provided an "affordable" enough way to do this operation. Jerry Schwarz AT&T Bell Labs, Murray Hill
mat@mole-end.UUCP (Mark A Terribile) (05/09/89)
In article <6590114@hplsla.HP.COM>, jima@hplsla.HP.COM (Jim Adcock) writes: > > It sure will. Pointers to virtual members are themselves virtual and go > > through the virtual tables. ... it imposes a couple of extra instructions > > of cost on every call-through-a-pointer-to-member-function if the class > > has *any* virtual members ... The cost really isn't that great. > Well, I find the cost somewhat discouraging ... > class baseclass > { > virtual int size(){return sizeof(baseclass);} > }; > . . . > baseclassptr->size(); Not relevant. This is pointer-to-object, NOT pointer-to-member. Pointer-to member isn't that common an operation: int (baseclass::*fn)() = &baseclass::size; i = (baseclass_obj.*fn)(); j = (baseclass_ptr->*fn)(); > For these simple get-a-value, put-a-value type virtual access functions > one could hope for code that compiles to a simple double indirection: > > baseclassptr->size(); > compiles to: > baseclassptr->(vtable+offset_of_size)->a_constant_equal_to_size; > or maybe even: > baseclassptr->vtable[offset_of_size_constant] > The present approach gives code that is about 10X slower than one > would hope for in these simple, everyday cases. True, this could be better implemented ASSUMING you know that all functions derived from this virtual member will be used in this way. All in all, the 10X cost is a matter of half-a-dozen extra instructions. Unless you can show that this is more than 2% of the cost of your program, I advise you not to worry about it. > Again, for OOP to be affordable, these simple, everyday "get" and > "put" type functionalities must be handled at minimal cost. > Otherwise programmers will violate strict encapsulation, and come > up with "hack" solutions. C++ is still at least an order of magnitude faster of Objective-C, and encourages this sort of interface. Objective-C doesn't seem to. -- (This man's opinions are his own.) From mole-end Mark Terribile
jima@hplsla.HP.COM (Jim Adcock) (05/10/89)
> >Again, for OOP to be affordable, these simple, everyday "get" and > >"put" type functionalities must be handled at minimal cost. > >Otherwise programmers will violate strict encapsulation, and come > >up with "hack" solutions. > > I get a frustrated by assertions of this kind. By any standard C++ > is "affordable", especially when compared to languages like Smalltalk > or Objective C. Note that the item I am replying to was sumbmitted > only to comp.lang.c++ so I have to read this as a suggestion that > C++ isn't "affortdable". (I suppose I could also read this as an > argument for my contention that C++ supports non object > oriented styles and therefore derives its affordability by avoiding > OOP when neccessary, but the tenor of the item I'm replying to > doesn't suggest that reading to me. I apologize if I'm misreading > Jim Adcocks note.) Sorry, I meant my comments in the context of the relative cost of virtual functions, compared to simple lookups as you discuss below: > In fact, C++ puts you at a low enough level so that (with out > violating the type discipline) it is possible to program the > operation under discussion (finding the "actual" size of an > object) as a simple lookup. > > class B > public > const size_t size ; > B(int i) : Size(i) ; > } ; > > class D : B { > D(...) : B(sizeof(D)) { ... } > } ; > > B* p ; ... p->size ... ; > > Yes, there is a certain amount of pain involved in programming this > explicitly. But recall that the original complaint was that C++ > doesn't provided an "affordable" enough way to do this operation. Again, the complaint is that virtual functions [as presently implemented in cfront with a pretty good backend C compiler] is too expensive relative to these simple lookups. While there are good optimizing C compilers out there, what they are good at optimizing is not the kind of code cfront produces. If you had a backend C compiler that can infer when to inline functions, or look at constant tables (as in vtables) and not add constants of zero, etc, etc, then you presumably could get some pretty good code when using cfront. Alternately, presumably, some of the kinds of optimizations specific to C++ could be put into cfront, and more general optimizations could be left to back end compilers. Unfortunately, at least when using K&R compilers for the back end, cfront knows a lot more about the code to be produced than the backend compiler. So cfront would be the place that a lot of the optimzations would have to occur. So, for example, right now, with my combination of cfront and back end compiler, Jerry's approach, where you violate the encapsulation of an object, access its instance variables directly, and lock future derived classes into using one approach to returning "size", and force a syntax of p->size rather than p->size() -- then generates code like such: movel a2@,sp@- Where as if one takes the "Object Oriented" approach of using virtual functions to return these values, so that some future class -- a linked list maybe -- can have a virtual function that calculates "p->size()" on the fly, then the [minimum] code that gets generated is: movel a3@(4),a0 addqw #8,a0 addw a0@,a3 movel a3,sp@- movel a0@(4),a0 jbsr a0@ | | V link a6,#0 movel a6@(8),a0 movel a0@,d0 unlk a6 rts | | V movel d0,sp@- So, as I was trying to say before, one can clearly see that attempts to encapsulate an object, accessing its instance variables using virtual functions, in order to allow flexibility in future derived classes, presently costs dearly; rather than just punting, and allowing direct access to some of an objects instance variables. About 10-20X slower. In many [most?] cases, a good optimizing C++ -> assembly compiler, or a good combination of a good optimizing C++ -> C and C -> asm compiler would be able to avoid generating most of this code most of the time. I don't see this is a problem with the language. Its just that C++ compilers need to do a better job of optimizing either the C or assembly code they produce. Its silly to pretend an optimizing C compiler is going to find all the optimizations possible out of the stuff cfront presently produces! While there are times when Jerry's suggestion is the way to go, there are also times when one would like to preserve the flexibility that virtual functions allow, and one would still be able to count on code being produced at minimum cost. The present 10-20X factor is simply too much. BUT: C++ is still much cheaper than Smalltalk and ObjC, even with the present weaknesses in the code produced.
jss@hector.UUCP (Jerry Schwarz) (05/10/89)
In article <6590118@hplsla.HP.COM> jima@hplsla.HP.COM (Jim Adcock) writes: class B { public const size_t size ; B(int i) : size(i) { } ; } ; class D : B { D(...) : B(sizeof(D)) { ... } } ; B* p ; ... p->size ... ; >Again, the complaint is that virtual functions [as presently implemented >in cfront with a pretty good backend C compiler] is too expensive >relative to these simple lookups. And my point is that C++ puts into the programmers hands the tools needed to generate whatever balance of lookup versus function calls is desired. > >So, for example, right now, with my combination of cfront and >back end compiler, Jerry's approach, where you violate the encapsulation >of an object, access its instance variables directly, and lock >future derived classes into using one approach to returning >"size", The design of classes that you intend to use as base classes is definitely non-trivial. The decision to "lock in" the derived classes in order to generate direct lookups for size, is a design decision that should be weighed carefully. I was illustrating how to implement it once it had been made. I'd like to emphasize this point, because I find it frequently overlooked. ********************************** The design of the "protected interface", which is what I call the interface between the base class and derived classes, requires careful consideration. One of C++ strengths is that it provides flexibility in specifying this interface. Consequently there is an obligation on the C++ programmer to use the flexibility wisely. ********************************** >and force a syntax of p->size rather than p->size() -- That was simply an omission to save a couple of lines in the example that I thought were irrelevant to the issues being discussed. What I would consider good style is something like class B { public: size_t size() { return x_size ; } protected: B(int i) : x_size(i) { } private: size_t x_size { } } ; Using C++ I can cause code to be generated as a direct lookup or as an indirect function call. Perhaps I've overlooked something. If Jim suggests an alternative kind of code I'll try to figure out a way to get it generated. I don't see how any amount of optimization in a compiler can do anything better unless the indirect function call is speeded up. A machine in which a virtual function call takes 20X a load is not a machine designed to run C++ code efficiently. Personally, I think his complaint is with the hardware designers. Maybe this discussion should be redirected to comp.arch :-) Jerry Schwarz AT&T Bell Labs, Murray Hill
jima@hplsla.HP.COM (Jim Adcock) (05/11/89)
> The design of the "protected interface", which is what I call the > interface between the base class and derived classes, requires > careful consideration. One of C++ strengths is that it provides > flexibility in specifying this interface. Consequently there is an > obligation on the C++ programmer to use the flexibility wisely. I would claim this obligation falls not simply on the programmer, but also on the C++ compiler designer, and on the person [say C ompiler desginer] who turns the intermediate representation into machine code. The C++ programmer should be free to specify flexibility where needed, and the C++ and C compilers should be smart enough not to use that flexibility where not need. Marking a function "virtual" should not be a unilateral declaration for C and/or C++ compilers to generate bad code. > Using C++ I can cause code to be generated as a direct lookup or as > an indirect function call. Perhaps I've overlooked something. If Jim > suggests an alternative kind of code I'll try to figure out a way to > get it generated. I don't see how any amount of optimization in a > compiler can do anything better unless the indirect function call is > speeded up. A machine in which a virtual function call takes 20X a > load is not a machine designed to run C++ code efficiently. > Personally, I think his complaint is with the hardware designers. > Maybe this discussion should be redirected to comp.arch :-) Hell, if hardware designers were forced to design new machines -- -- and customers were forced to buy them -- everytime someone dreamed up a new language -- then even ObjC could run quickly! I have no problem with C++ *the language*, it *can* be efficiently implemented on today's machine -- I just haven't yet seen a C++ compiler that *does* implement major details of the language efficiently. The biggest disappointment so far is unnecessary expansion of inline virtual functions into table lookup + indirect function calls. Again, if one declares a "virtual function" for size inline; if that inline function just returns a value; and if which virtual function needs actually be called can be uniquely determined at compile time -- then one could hope the assembly that gets generated would be: movel a2@,sp@- Whereas, what *I* *always* get, no matter *how* I call a virtual function [from *my* combination of C++/C compilers] is: movel a3@(4),a0 addqw #8,a0 addw a0@,a3 movel a3,sp@- movel a0@(4),a0 jbsr a0@ | | V link a6,#0 movel a6@(8),a0 movel a0@,d0 unlk a6 rts | | V movel d0,sp@- which is 11 assembly instructions rather than one. I am not about to bother trying to count clock cycles associated with these sequences, but my guess is with the greater complexity of the instructions in the second sequence, the higher chance of cache misses, etc, the second sequence is actually about 20X the first [single instruction] sequence. Looking at the second sequence, one sees that really the assembly code generator ought to be smart enough to leave out the link/unlk sequence, and return the value stack relative [unfortunately, most code generators I've seen are reluctant to do this]: movel a3@(4),a0 addqw #8,a0 addw a0@,a3 movel a3,sp@- movel a0@(4),a0 jbsr a0@ | | V movel sp@(8),a0 movel a0@,d0 rts | | V movel d0,sp@- This would save about 20% of the cost. Next, the C++ compiler should be smart enough to recognize the frequent situation where multiple inheritence is not being used: movel a3@(4),a0 jbsr a0@ | | V movel sp@(8),a0 movel a0@,d0 rts | | V movel d0,sp@- This would save about another 20-30% of the cost. Finally, simply declaring a function "virtual" should not "poison" the function, forcing the full table lookup indirect function call sequence returning a single value, when from context the C++ compiler can determine which [inline] virtual function actually needs to be called. So frequently, the code sequence could be reduced to: movel a2@,sp@- In summary, common optimizing "code generators" [C compilers] are not well suited to the unique needs of generating C++ code, and C++ compilers are not giving the code generators particularly good C code to begin with. To really "support" object oriented programming in C++, virtual functions need to be implemented more efficiently. Programmers should not be unnecessarily forced to make functions non-virtual simply because of the inefficiencies of existing C++ front ends or C back ends. Both need to be better.
jss@hector.UUCP (Jerry Schwarz) (05/11/89)
In article <6590119@hplsla.HP.COM> jima@hplsla.HP.COM (Jim Adcock) writes: > >I have no problem with C++ *the language*, it *can* be efficiently >implemented on today's machine -- I just haven't yet seen a C++ >compiler that *does* implement major details of the language efficiently. This was not at all clear from your earlier remarks (at least not to me.) My earlier notes were addressing language design issues, not optimization issues. Complaints about the quality of optimizations of compilers ought to specify what compiler you're complaining about. > >The biggest disappointment so far is unnecessary expansion of >inline virtual functions into table lookup + indirect function calls. > You may be happy to learn that the pre-release 2.0 does expand virtual functions inline when it can determine the correct version. struct K { virtual int size() { return sizeof(K) ; } ; } ; void g() { K k ; int s = k.f() ; // this is expanded into a simple // assignment in sizeof(struct K) } Jerry Schwarz AT&T Bell Labs, Murray Hill
jjc@jclark.UUCP (James Clark) (05/11/89)
In article <6590114@hplsla.HP.COM> jima@hplsla.HP.COM (Jim Adcock) writes: Well, I find the cost somewhat discouraging if all one is trying to do is return a value from an object of uncertain class. For example, try to find an inexpensive way to get a hierarchy of classes to return information about their sizes -- presumably: class baseclass { virtual int size(){return sizeof(baseclass);} }; class derivedclass : baseclass { int size(){return sizeof(derivedclass);} } For these simple get-a-value, put-a-value type virtual access functions one could hope for code that compiles to a simple double indirection: baseclassptr->size(); compiles to: baseclassptr->(vtable+offset_of_size)->a_constant_equal_to_size; or maybe even: baseclassptr->vtable[offset_of_size_constant] One way to handle this might be to extend the language to support virtual static const data members: virtual in that accesses to them go through the vtable, static in that they are per class rather than per instance. Then one could say: struct baseclass { virtual static const int size = sizeof(baseclass); }; struct derivedclass : baseclass { static const int size = sizeof(derivedclass); }; One would be able to access such a member like any normal data member of the class. James Clark jjc@jclark.uucp
mat@mole-end.UUCP (Mark A Terribile) (05/11/89)
> > >Again, for OOP to be affordable, these simple, everyday "get" and > > >"put" type functionalities must be handled at minimal cost. > > I get a frustrated by assertions of this kind. By any standard C++ > > is "affordable", ... > Sorry, I meant my comments in the context of the relative cost of > virtual functions, compared to simple lookups as you discuss below: [Virtual function calls when all that's needed is a stored value representing ``sizeof''] > ... Unfortunately, at least when using K&R compilers for the back end, > cfront knows a lot more about the code to be produced than the backend > compiler. So cfront would be the place that a lot of the optimzations > would have to occur. I think that this is wrong. Remember that anywhere the class is visible, a programmer may derive a new class with a replacement function that can't be implemented as a constant lookup. The only way to avoid this is to make the original base class promise that this won't be done, and then to enforce the promise. This means a *declaration* to that effect. What you really want, I think, is a virtual const. I think it's a neat idea and useful for certain purposes, *but* it's a new language feature and implementing every feature that might be composed at the fringe of the language smacks of PL/I. Have we forgotten wher *that* leads? Allowing the constructor to initialize a const member with the sizeof is, all in all, a reasonable idea, except that it only works for the base that owns that member. It has to be written as an assignment, I believe. (Still not too bad, though not quite as safe in the face of program changes.) -- (This man's opinions are his own.) From mole-end Mark Terribile
mat@mole-end.UUCP (Mark A Terribile) (05/11/89)
[The debate about how to store and access the size of an object in an inheritance tree ... or anything else that is constant per base or derived type ...] > So, for example, right now, with my combination of cfront and back end > compiler, Jerry's approach, where you violate the encapsulation of an > object, access its instance variables directly, and lock future > derived classes into using one approach to returning "size", and force > a syntax of p->size rather than p->size() -- First, I think that Jerry's article about the protected interface and its intended customers answers this. It is often reasonable to make a design decision, in a particular circumstance, that constrains you later in some way. OOP people would like to have total code reusability. The problem with this approach is that the underlying algorithms have widely varying time and space properties and one solution is *rarely* correct for everything. See grep(1) on a version of ``The UNIX (tm, etc.) Time Sharing System.'' See the debate now raging on comp.lang.c about free store management. Sometimes you have to pay a price in generality to get performance. C++ allows you to make these decisions; it does not force the answers on you. > For crying out loud! If you are so concerned about performance that > you would be willing to rape your code if it saved you a few cycles, > how about this radical approach: write in the object oriented style, > AND GET A REAL MACHINE. ... The job of the engineer is to move those cost/performance/reliability curves that he can to the best advantage. That doesn't mean that he can change his environment. If there is a glut of cheap 8088s around, he can build a cheaper product, sell more, and thereby pay for more effort to improve the performance and reliability. He can also return more money to the stockholders, who will respond by asking him to do something else that they find useful (i.e. profitable to them and *presumably* to the people who buy the product because they find it useful). The discussions here show that C++, by not imposing its own ``compleat'' definition of OOP, is engendering all sorts of interesting debate about how OOP can be used to real effect in the real world. THIS IS GOOD. On the other hand, using the word ``rape'' to describe consensual union between those who (presumably) have the right to that union is distortion and pointless inflammation of passions. -- (This man's opinions are his own.) From mole-end Mark Terribile
jima@hplsla.HP.COM (Jim Adcock) (05/12/89)
> In article <6590119@hplsla.HP.COM> jima@hplsla.HP.COM (Jim Adcock) writes: > > > >I have no problem with C++ *the language*, it *can* be efficiently > >implemented on today's machine -- I just haven't yet seen a C++ > >compiler that *does* implement major details of the language efficiently. > > This was not at all clear from your earlier remarks (at least not to > me.) My earlier notes were addressing language design issues, not > optimization issues. I'm a language user, not a designer. Either give me the constructs I need to use the language efficiently, or make compilers smart enough to optimize out excess generality where it's not needed. Allowing access to members [at least statics] through the vtable would be one step in the right direction. Or having a compiler smart enough to inline virtual functions where one could reasonably expect to see inlined virtual functions would be another step in the right direction. Personally, I believe that it is better if most of these smarts are in the compiler. Compilers that figure out what to register, for example, rather than having to specify what a user wants to "register", is an old example from the "C" world. > Complaints about the quality of optimizations > of compilers ought to specify what compiler you're complaining about. I agree Jerry. And as I've complained to you before, I ought to be able to discuss these things freely [like what compiler I'm using] -- especially since people at AT&T are discussing these things freely. But agreements between AT&T and HP prevent me from discussing these things freely -- I've gotten my hands slapped before. And then *you* complain about my inability to discuss these things freely. I think that is unfair. If AT&T people are free to discuss these things, then so should I be. How about calling off your lawyers, so that we can discuss these things publicly? > >The biggest disappointment so far is unnecessary expansion of > >inline virtual functions into table lookup + indirect function calls. > > You may be happy to learn that the pre-release 2.0 does expand > virtual functions inline when it can determine the correct version. > > struct K { > virtual int size() { return sizeof(K) ; } ; > } ; > > void g() { > K k ; > int s = k.f() ; > // this is expanded into a simple > // assignment in sizeof(struct K) > } > Okay, so perhaps you can tell us whether the release version of 2.0 will be able to inline in the following almost-as-trivial situation: class K { public: virtual int size() { return sizeof(K) ; } ; } ; class L { int stuff; public: virtual int size() { return sizeof(L) ; } ; } ; void g() { K k; L l; int s = k.size() ; // is this example expanded into a simple // assignment in sizeof(struct K) ??? // Why, or Why Not ??? } Please test this example before you answer. When 2.0 does comes out, how are people going to know what it can, or can't do? Are some of these important issues going to be openly addressed? Can we get a list of what new features are, or are not going to be in 2.0? Can we get a list of limitations on 2.0 -- where or where not will it be smart enough to inline, for example? Or are customers expected to buy a pig in a poke?
jima@hplsla.HP.COM (Jim Adcock) (05/12/89)
And while I'm asking for some C++ optimizations, is it possible that we will ever see a compiler that doesn't make gratuitous use of the & operator in the C code it generates? Code fragments like: (& __1glop) -> __gloop instead of: __1glop . __gloop And: (( __1thisglop = __1thatglop ) , & __1thisglop ) ; Instead of: ( __1thisglop = __1thatglop ) ; guarantees (in the optimizing C compilers that I know of) that the structures whose address is taken actually exists and resides in memory. Whereas, without the & operator, the structures [if small] may reside in registers, and maybe only those fields of the "structure" that are actually used. Also & __1glop, where neither & __1glop nor __1glop ever actually get used, still causes space on the stack for __1glop to be allocated. While one might claim that optimizing C compilers shouldn't interpret &something to mean that something has to be -- and be in memory, this has been the traditional interpretation of & in C. Seems like C++ should be able to be smart enough to avoid gratuitous & operators, and comma expressions whose return values are clearly not used.
jss@hector.UUCP (Jerry Schwarz) (05/12/89)
In article <6590121@hplsla.HP.COM> jima@hplsla.HP.COM (Jim Adcock) writes: > >Okay, so perhaps you can tell us whether the release version of 2.0 >will be able to inline in the following almost-as-trivial situation: ... I was going to ignore that question, because I cannot make any commitments about the released 2.0. However, for the record, I ran that code and the current cfront installed on my machine inlines the call of k.size(). I personally doubt that this optimization is important. In practice I believe very few calls to virtual functions are even theoretically inlinable. Jerry Schwarz AT&T Bell Labs, Murray Hill
rfg@riunite.ACA.MCC.COM (Ron Guilmette) (05/14/89)
In article <6590121@hplsla.HP.COM> jima@hplsla.HP.COM (Jim Adcock) writes: > >I agree Jerry. And as I've complained to you before, I ought to be able >to discuss these things freely [like what compiler I'm using] >-- especially since people at AT&T are discussing these things freely. >But agreements between AT&T and HP prevent me from discussing these >things freely -- I've gotten my hands slapped before. >And then *you* complain about my inability >to discuss these things freely. I think that is unfair. If AT&T >people are free to discuss these things, then so should I be. How >about calling off your lawyers, so that we can discuss these things >publicly? Jim, If you are really getting hassled for simply trying to get some facts about cfront 2.0 out in the broad daylight, then that is obviously a travesty. I am reminded of the DoD's tendency to cloak even the most innocent research in secrecy. I believe that many uproars have been caused by the DoD barring foreigners from various conferences, etc. The uproar comes when people realize that a free flow of information is one of the fundamental ingredients of progress. I believe that that applies to C++ as well. >When 2.0 does comes out, how are people going to know what it can, >or can't do? Try it! Then post your results here. I'm sure that a lot of us (me especially) would like to see some good test cases posted here which show either things that do work or things that don't. >Are some of these important issues going to be >openly addressed? I believe that that is what this newsgroup is for. >Can we get a list of what new features are, >or are not going to be in 2.0? Correct me if I'm wrong, but I believe that it has been stated here (several times) already that a description of 2.0 features will be posted here at about the time of the release. >Can we get a list of limitations >on 2.0 ... Does HP publish such lists for its own software products? I think not. Let he who is without sin cast the first stone. In general, I expect hell to freeze over before total honesty with customers becomes the norm in the software end of the business. >Or are customers expected to buy a pig in a poke? No. If you think that you are being mislead I suggest that you *not* buy the product. -- // Ron Guilmette - MCC - Experimental Systems Kit Project // 3500 West Balcones Center Drive, Austin, TX 78759 - (512)338-3740 // ARPA: rfg@mcc.com // UUCP: {rutgers,uunet,gatech,ames,pyramid}!cs.utexas.edu!pp!rfg
jss@hector.UUCP (Jerry Schwarz) (05/14/89)
In article <205@riunite.ACA.MCC.COM> rfg@riunite.UUCP (Ron Guilmette) writes: > >If you are really getting hassled for simply trying to get some facts >about cfront 2.0 out in the broad daylight, then that is obviously a >travesty. This is exactly the problem. There are no "facts about 2.0" because 2.0 does not yet exist. This is not facetious, many of the questions people have about detailed coding issues have only recently been settled. It is also not completely hypothetical. Its pretty clear (from the earlier items in this discussion) Ron has wanted to say "2.0 never inlines calls to virtual members, even when it should know which version is required". But since the current version on my system does do such inlining it seems likely that this will not be true of 2.0. Jerry Schwarz AT&T Bell Labs, Murray Hill
jima@hplsla.HP.COM (Jim Adcock) (05/15/89)
> If you are really getting hassled for simply trying to get some facts > about cfront 2.0 out in the broad daylight, then that is obviously a > travesty. I am reminded of the DoD's tendency to cloak even the most > innocent research in secrecy. I believe that many uproars have been > caused by the DoD barring foreigners from various conferences, etc. > The uproar comes when people realize that a free flow of information > is one of the fundamental ingredients of progress. I believe that > that applies to C++ as well. Well, again, my frustration is that AT&T people are able to comment openly on 2.0, and I'm not. I can appreciate that company's have many legitimate and illigitamate reasons to keep new product releases quiet, but to have AT&T people be able to comment, and not I, I find frustrating. Either the cat in the bag, or out of the bag -- but halfway is too wierd. Not to imply 2.0 was ever *in* the bag. Regards "free flow of information," I feel once 2.0 is discussed on notes, then I should be free to discuss it too. But I haven't gotten permission to do so. And so since I don't like being stomped on, I feel this continuing frustration of not being to speak freely. I continue to believe that the main source of this problem is a failure to cleanly differentiate between C++ *the language* and C++ *vendor XYZ's product*. > >When 2.0 does comes out, how are people going to know what it can, > >or can't do? > > Try it! Then post your results here. I'm sure that a lot of us > (me especially) would like to see some good test cases posted > here which show either things that do work or things that don't. I'm getting sick and tired trying to reverse engineer C++ compilers -- including g++. [By reverse engineer I mean trying to understand what kind of code its going to produce in various situations.] Does the language include such-a-such? Write code to try it. Then unscamble the so-called "C" code that the AT&T compiler produces. Or stare at the assembly g++ produces. Did you make a mistake in your coding? Does the compiler have a bug? Is this an unimplemented feature? Did you misunderstand that feature of the language? Can you mentally uncipher the name encodings used? Is this a "feature" of the language or the compiler you're fighting with. Etc, etc, etc. Wouldn't it be easier if compiler writers just wrote a 20 page user's guide that states how their compilers handles various major issues in C++? In-line functions? Virtual functions? Name encoding? Operator overloading? etc? Multiple inheritence? Parameterized classes? .....Rather than forcing each user to try to reverse engineer these things on each compiler on each new release? > Does HP publish such lists for its own software products? I think > not. Let he who is without sin cast the first stone. In general, > I expect hell to freeze over before total honesty with customers > becomes the norm in the software end of the business. There certainly are some such lists for some such software products. If anyone needs any information on HP products, I, among many others, will do their best to get it for you. My phone number is (206)-335-2138. But, I cannot pretend to represent HP. I am one person in 100,000. Gnu people seem to confuse individuals with the companies they work for. Which is strange -- at least unless those individuals confuse themselves with the company they work for. The above is not to imply I'm satisfied with the way HP does business. I'm not. For example, I'd like HP to support C++ directly.... If we waited for people without sin to throw the first stone, there would be no notes discussions. Total honesty is like the skins of an onion. I do not see software as more dishonest than other businesses. Like real estate :-) > >Or are customers expected to buy a pig in a poke? > > No. If you think that you are being mislead I suggest that you *not* > buy the product. I look forward to the day when I can get "complete" C++ compilers from a dozen vendors. Presently my two choices are from AT&T and Gnu. Which sometimes feels like getting stuck between a rock and a hard place. No matter whose compiler I use I am forced to "buy" into learning it, and "reverse engineering it." Which is the true cost. I trust C++ *the language* and feel it is headed in the right direction. I feel frustrated by C++ *the vendor XYZ's product* [incl Gnu], which are not well enough supported for my tastes. Recent software reviews seem to echo these frustrations.
jima@hplsla.HP.COM (Jim Adcock) (05/18/89)
> The folks from AT&T have stated, in this newsgroup, on several > occasions, that they are working on a complete reference manual for > C++, intended to provide a full specification of the language. They > already know that such a thing is urgently needed; it won't do any > good to keep reminding them. I'm as eager to receive a final and > complete spec as everyone else, but I understand that these things are > quite a lot of work, and they take time. I'm not talking about a complete up-to-date language reference -- although g*d knows we need such a thing. I'm talking about a reference on how a *compiler* "works" -- what kind of code it generates, and why, in a variety of situations? And what are its limitations, where does it fail to generate code? The areas I listed before are what confuses me the most about existing compilers -- also how they handle automatic generation of functions to handle assignment, initialization, how temporaries are handled etc. I can make little changes in C++ code, and get radically differing results in the code generated -- for no apparent reasons. There are many situations where I have not been able to "reverse engineer" what is going on. It would be nice to know. The code generation issues are much more complex in C++ than in C. It's important to know how a compiler is going to handle various situations, and how the various compilers differ.
dlw@odi.com (Dan Weinreb) (05/18/89)
In article <6590126@hplsla.HP.COM> jima@hplsla.HP.COM (Jim Adcock) writes:
Wouldn't it be easier if compiler writers just wrote a 20 page user's guide
that states how their compilers handles various major issues in C++?
In-line functions? Virtual functions? Name encoding? Operator overloading?
etc? Multiple inheritence? Parameterized classes? .....Rather than forcing
each user to try to reverse engineer these things on each compiler on each
new release?
The folks from AT&T have stated, in this newsgroup, on several
occasions, that they are working on a complete reference manual for
C++, intended to provide a full specification of the language. They
already know that such a thing is urgently needed; it won't do any
good to keep reminding them. I'm as eager to receive a final and
complete spec as everyone else, but I understand that these things are
quite a lot of work, and they take time.
I trust C++ *the language* and feel it is headed in the right direction.
I feel frustrated by C++ *the vendor XYZ's product* [incl Gnu], which are
not well enough supported for my tastes. Recent software reviews seem
to echo these frustrations.
Yes, the state of things right at the moment is not very good for the
present users; things are still young, and the users are still
pioneers to some extent. I think most of us are using C++ because we
are reasonably confident that the vendors intend to put in the effort
to stabilize the language definition, and produce compilers and other
tools that will be mature and well-debugged.
The user community should try to provide criticism and feedback that
is productive and useful to the implementors, such as specific bug
reports, feedback about what language features seem to be particularly
confusing or troublesome, indications of what needs users have that
are not being fulfilled by the present language/compiler, etc. That's
the best way we can encourage them, and help them produce the
high-quality product that we're all looking forward to.
Dan Weinreb Object Design, Inc. dlw@odi.com