andrew@resam.dk (Leif Andrew Rump) (01/24/91)
I experienced a rather annoying feature in TurboPascal 5.5 (but I
think the problem may exist in a lot of other (integrated) debuggers
used to debug object oriented programmes.
The program enclosed create two (2) dynamic objects: a square & a
box.
The first thing to notice is that the compiler only allow squareptr
to be used as a general object for squares & boxes! Well I could
accept that _IF_ the debugger (integrated & external (TD)) at least
would notice when I create a box! But no - it only display the
content of a square - the length has to be extracted manually!!!
program dynamic;
type
generalptr = ^general;
general =
object
destructor done; virtual;
end;
squareptr = ^square;
square =
object(general)
height, width : real;
constructor init(h, w : real);
end;
boxptr = ^box;
box =
object(square)
length : real;
constructor init(h, w, l : real);
end;
destructor general.done; begin end; (* everything is done behind our back *)
constructor square.init(h, w : real);
begin
height := h;
width := w;
end;
constructor box.init(h, w, l : real);
begin
square.init(h, w);
length := l;
end;
const
n = 2;
var
general_object : array(.1..n.) of squareptr;
nr : integer;
begin
for nr := 1 to n do
if odd(nr) then
general_object(.nr.) := new(squareptr, init(3, 4))
else
general_object(.nr.) := new(boxptr, init(3, 4, 2));
for nr := 1 to n do
dispose(general_object(.nr.), done);
end.
Leif Andrew Rump, AmbraSoft A/S, Stroedamvej 50, DK-2100 Copenhagen OE, Denmark
UUCP: andrew@ambra.dk, phone: +45 39 27 11 77 /
Currently at Scandinavian Airline Systems =======/
UUCP: andrew@resam.dk, phone: +45 32 32 51 54 \
SAS, RESAM Project Office, CPHML-V, P.O.BOX 150, DK-2770 Kastrup, Denmark
> > Read oe as: o <backspace> / (slash) and OE as O <backspace> / (slash) < <
bytor@ctt.bellcore.com (Ross Huitt) (01/25/91)
In article <1991Jan24.152256.24273@resam.dk> andrew@resam.dk (Leif Andrew Rump) writes: >I experienced a rather annoying feature in TurboPascal 5.5 (but I >think the problem may exist in a lot of other (integrated) debuggers >used to debug object oriented programmes. >The program enclosed create two (2) dynamic objects: a square & a >box. >The first thing to notice is that the compiler only allow squareptr >to be used as a general object for squares & boxes! Well I could >accept that _IF_ the debugger (integrated & external (TD)) at least >would notice when I create a box! But no - it only display the >content of a square - the length has to be extracted manually!!! > ...code deleted > >Leif Andrew Rump, AmbraSoft A/S, Stroedamvej 50, DK-2100 Copenhagen OE, Denmark >UUCP: andrew@ambra.dk, phone: +45 39 27 11 77 / >Currently at Scandinavian Airline Systems =======/ >UUCP: andrew@resam.dk, phone: +45 32 32 51 54 \ >SAS, RESAM Project Office, CPHML-V, P.O.BOX 150, DK-2770 Kastrup, Denmark > >> > Read oe as: o <backspace> / (slash) and OE as O <backspace> / (slash) < < When I _know_ which derived class a base class ptr is pointing to and I want to inspect or display the object as a derived class, a cast is usually sufficient to get the job done. With the Turbo products, simply type in 'squareptr(general_object(1))' at the Display or Evaluate prompts. I don't know for sure that the technique works with Turbo Pascal or if this particular syntax is correct, but I do use the technique with C++ frequently. -ross aka bytor@ctt.bellcore.com
andrew@resam.dk (Leif Andrew Rump) (01/28/91)
In <1991Jan25.145947.16431@bellcore.bellcore.com> bytor@ctt.bellcore.com (Ross Huitt) writes: >In article <1991Jan24.152256.24273@resam.dk> andrew@resam.dk (Leif Andrew Rump) writes: >>I experienced a rather annoying feature in TurboPascal 5.5 (but I >>think the problem may exist in a lot of other (integrated) debuggers >>used to debug object oriented programmes. >>The program enclosed create two (2) dynamic objects: a square & a >>box. >>The first thing to notice is that the compiler only allow squareptr >>to be used as a general object for squares & boxes! Well I could >>accept that _IF_ the debugger (integrated & external (TD)) at least >>would notice when I create a box! But no - it only display the >>content of a square - the length has to be extracted manually!!! >> >...code deleted >> >When I _know_ which derived class a base class ptr is pointing to >and I want to inspect or display the object as a derived class, a cast >is usually sufficient to get the job done. With the Turbo products, >simply type in 'squareptr(general_object(1))' at the Display or >Evaluate prompts. I don't know for sure that the technique works with >Turbo Pascal or if this particular syntax is correct, but I do use the >technique with C++ frequently. But, but, but, ... Why can't the debugger that has _all_ the information do this job! The main reason for me to write this letter was that one of my programmes used a dynamic list of objects and if I was going to use the debugger to show me the content of for example the first three objects in a list a had to remember what type each object was and change casts accordingly - then (as I wrote in my original letter) I surely sill make mistakes and then the debugger only caused havoc!!! Leif Andrew Leif Andrew Rump, AmbraSoft A/S, Stroedamvej 50, DK-2100 Copenhagen OE, Denmark UUCP: andrew@ambra.dk, phone: +45 39 27 11 77 / Currently at Scandinavian Airline Systems =======/ UUCP: andrew@resam.dk, phone: +45 32 32 51 54 \ SAS, RESAM Project Office, CPHML-V, P.O.BOX 150, DK-2770 Kastrup, Denmark > > Read oe as: o <backspace> / (slash) and OE as O <backspace> / (slash) < <
bytor@ctt.bellcore.com (Ross Huitt) (01/28/91)
In article <1991Jan28.100213.1822@resam.dk> andrew@resam.dk (Leif Andrew Rump) writes: >In <1991Jan25.145947.16431@bellcore.bellcore.com> bytor@ctt.bellcore.com (Ross Huitt) writes: > >>When I _know_ which derived class a base class ptr is pointing to >>and I want to inspect or display the object as a derived class, a cast >>is usually sufficient to get the job done. > >But, but, but, ... Why can't the debugger that has _all_ the information >do this job! The main reason for me to write this letter was that one >of my programmes used a dynamic list of objects and if I was going to >use the debugger to show me the content of for example the first three >objects in a list a had to remember what type each object was and change >casts accordingly - then (as I wrote in my original letter) I surely >sill make mistakes and then the debugger only caused havoc!!! > >Leif Andrew > >UUCP: andrew@resam.dk, phone: +45 32 32 51 54 \ >> > Read oe as: o <backspace> / (slash) and OE as O <backspace> / (slash) < < The debugger does not necessarily have _all_ of the information for objects that are dyanmically allocated. If a derived object is later referenced by a base pointer the only piece of information I can think of that a debugger could use to determine the compile-time type of would be the pointer to the virtual function table. If the classes involved don't have a virtuals then even this won't work. (I know there are other cases, too, so don't bother flaming me.) To accomplish what you want would require support from the compiler such as embedding a class signature in each instance of a class. The debugger would then read this signature to determine the class of the object regardless of the class of the pointer. This level of meta-class support would be very welcome especially if we programmers had access to it. Its one aspect of Smalltalk that I miss very much in C++. BTW, there are programming techniques that you can use to determine the classes of your objects at run time. You would still have to use casts in the debugger, but at least you could execute a member function to determine the class of the object before you used a cast. -bytor@ctt.bellcore.com
mas@genrad.com (Mark A. Swanson) (01/29/91)
Determining what a dynamic object is is not always possible in raw C++. However, if one is developing within a development environment with a standard set of object coding conventions (e.g. a required char *myclass() method) an integrated debugger can use them to provide such functionality. Such a layered approach is practical now and avoids having to wait years for invention and agreement on how best to support meta-identities without adding to C++'s minimal object overhead.
shankar@hplego.cup.hp.com (Shankar Unni) (01/30/91)
bytor@ctt.bellcore.com (Ross Huitt) writes: > >But, but, but, ... Why can't the debugger that has _all_ the information > >do this job! [ ... ] > The debugger does not necessarily have _all_ of the information for > objects that are dyanmically allocated. If a derived object is later > referenced by a base pointer the only piece of information I can > think of that a debugger could use to determine the compile-time type of > would be the pointer to the virtual function table. If the classes > involved don't have a virtuals then even this won't work. [...] The HP C++ debugger (on HP-UX) uses exactly this sort of scheme to figure out what the real type of the object is. And of course, as you point out, if the classes involved do not have any virtual functions, it is helpless as far as figuring out the "real type". In the latter case, it is possible to rationalize this behavior by saying that the program itself cannot distinguish between a base_ptr pointing to a base and a base_ptr pointing to a derived when there are no virtual functions involved... (Of course, the compiler could have gone and stuck a type-id into each object, but that would break lots of other things) ----- Shankar Unni E-Mail: Hewlett-Packard California Language Lab. Internet: shankar@hpda.hp.com Phone : (408) 447-5797 UUCP: ...!hplabs!hpda!shankar DISCLAIMER: This response does not represent the official position of, or statement by, the Hewlett-Packard Company. The above data is provided for informational purposes only. It is supplied without warranty of any kind.
tma@m5.COM (Tim Atkins) (02/28/91)
In article <40541@genrad.UUCP> mas@crom.genrad.COM (Mark A. Swanson) writes: >Determining what a dynamic object is is not always possible in raw C++. >However, if one is developing within a development environment with a standard >set of object coding conventions (e.g. a required char *myclass() method) >an integrated debugger can use them to provide such functionality. > >Such a layered approach is practical now and avoids having to wait years >for invention and agreement on how best to support meta-identities without >adding to C++'s minimal object overhead. I fail to understand the phrase "minimal object overhead" regarding C++. Surely such can not be claimed in terms of space. If one cares about issues of polymorphism for a given set of classes then each instance will contain an overhead of at least a 4 byte virtual table pointer for every class in its inheritance hierarchy than defines virtual functions. In comparison, languages that only include a single pointer to the object's class where information allowing message binding is to be found are much more minimal in terms of space overhead. Nor is this the complete story on C++ space overhead. Due to the way MI is implemented in relation to the implementation requirement that all superclass variables be contiquous, it is quite possible that there is duplication of entire substructures in the C++ instance. I understand that the goal of these implementation practices is greater run-time efficiency, but certainly no one should claim they came without price nor that C++ acheives "minimal object overhead". I also have considerable problem with C++ in that given an instance one cannot know its class at run-time. In my view this means that the object is in some sense not truly first class and posseses only a partial identity. Among other problems this totally blows away encapsulation in that the behavior of the object and indeed any metalevel information is known only to the compiler. Even within cfront this information is never explicitly present from what I have seen. C++ instances are really only data structures with most of their knowledge not present at all within running programs. They are not objects in the sense that they have knowledge present within themselves (or their class) of their own structure or behavior. They literally do not know what they are. - Tim
jbuck@galileo.berkeley.edu (Joe Buck) (03/01/91)
In article <4578@m5.COM>, tma@m5.COM (Tim Atkins) writes: |> I fail to understand the phrase "minimal object overhead" regarding |> C++. Surely such can not be claimed in terms of space. If one cares |> about issues of polymorphism for a given set of classes then each instance |> will contain an overhead of at least a 4 byte virtual table pointer for |> every class in its inheritance hierarchy than defines virtual functions. Perhaps an implementation could be written this way, but both cfront and g++ use only a single pointer per object, regardless of its class hierarchy. |> In comparison, languages that only include a single pointer to the object's |> class where information allowing message binding is to be found are much |> more minimal in terms of space overhead. You've just described C++ (there is only a single pointer to the object's virtual function table per object in most implementations, and there is only one virtual function table per class). However, since C++ also allows classes with no virtual functions, it's possible to have no overhead at all. !> Nor is this the complete story |> on C++ space overhead. Due to the way MI is implemented in relation to |> the implementation requirement that all superclass variables be contiquous, |> it is quite possible that there is duplication of entire substructures |> in the C++ instance. I understand that the goal of these implementation |> practices is greater run-time efficiency, but certainly no one should |> claim they came without price nor that C++ acheives "minimal object |> overhead". Will you actually learn the language before you criticize it? You're stating imaginary requirements and reaching false conclusions. Base classes can be declared as virtual and shared if desired in multiple inheritance hierarchies. Alternatively, there can be duplication if the programmer chooses. All of these "wasted space" arguments you're making are based on misunderstandings of the language. There is no implementation requirement that all superclass variables be continuous. |> I also have considerable problem with C++ I think I'll just cut you off right there. It seems appropriate. :-) C++ certainly has flaws, but you aren't yet competent enough to write about them since your understanding of the language has serious holes. -- Joe Buck jbuck@galileo.berkeley.edu {uunet,ucbvax}!galileo.berkeley.edu!jbuck
peter@prefect.Berkeley.EDU (Peter Moore) (03/02/91)
In article <4578@m5.COM>, tma@m5.COM (Tim Atkins) writes: |> I fail to understand the phrase "minimal object overhead" regarding |> C++. Surely such can not be claimed in terms of space. If one cares |> about issues of polymorphism for a given set of classes then each instance |> will contain an overhead of at least a 4 byte virtual table pointer for |> every class in its inheritance hierarchy than defines virtual functions. You are mistaking features of one particular implementation of C++ with features of the language itself. Virtual tables (vtbls for short) ARE NOT PART OF THE LANGUAGE. They are merely one way of implementing the virtual function behavior of the language. Secondly, the particular implementation you are probably refering to, cfront from ATT, does NOT have a vtbl pointer for every super class that has virtual functions. In the single inheritance case, there is atmost one vtbl pointer no matter how many classes in the inheritance chain have virtual functions. Multiple inheritance is more complicated. |> Due to the way MI is implemented in relation to |> the implementation requirement that all superclass variables be contiquous, |> it is quite possible that there is duplication of entire substructures |> in the C++ instance. Again, this is NOT A CHARACTERISTIC of the langauge. The people at Tau Metric and Oregon Software would probably be glad to tell you about how their compiler doesn't make any redundant copies of base classes. Peter Moore
jimad@microsoft.UUCP (Jim ADCOCK) (03/05/91)
Sorry, but I really have to question how familiar this poster is with C++: In article <4578@m5.COM> tma@m5.UUCP (Tim Atkins) writes: |I fail to understand the phrase "minimal object overhead" regarding |C++. Surely such can not be claimed in terms of space. If one cares |about issues of polymorphism for a given set of classes then each instance |will contain an overhead of at least a 4 byte virtual table pointer for |every class in its inheritance hierarchy than defines virtual functions. I have never seen any C++ compiler that requires 4 bytes per object per class in the inheritence hierarchy. Most C++ objects as compiled by most C++ compilers only require a 2/4 byte overhead per object regardless of how many classes are in the inheritence hierarchy. This is regardless of how many places in the inheritence hierarchy virtual functions are defined. In the infrequent case of multiple inheritence, one common C++ implementation scheme requires a extra 2/4 byte overhead per additional class being immediately [multiply] inherited from. But this is still far less than the 4 bytes per class in the inheritence hierarchy you claim. |In comparison, languages that only include a single pointer to the object's |class where information allowing message binding is to be found are much |more minimal in terms of space overhead. Nor is this the complete story |on C++ space overhead. Due to the way MI is implemented in relation to |the implementation requirement that all superclass variables be contiquous, |it is quite possible that there is duplication of entire substructures |in the C++ instance. C++ does not require that all superclass variables be contiguous. Rather, it only requires variables declared within one labeled section within one class declaration be contiguous. C++ substructures are duplicated if C++ programmers require substructures be duplicated. If C++ programmers desire substructures be shared, that can also be specified. |I understand that the goal of these implementation |practices is greater run-time efficiency, but certainly no one should |claim they came without price nor that C++ acheives "minimal object |overhead". I will not claim that the common C++ implemetation choices come without price, but I will claim that C++ remains a leader in OOPL language efficiency, and that is why more people are using C++ than any other OOPL. Most C++ objects have a single 2/4 byte "vtable ptr" used to represent their class type, and require one extra indirection for virtual function dispatch. This is not minimal -- its just a lot better than just about all other OOPLs. In addition, in many simple situations C++ inline functions can be used, frequently execution 20-100 times faster than C++ virtual funtions, which in turn makes them 200-1000 times faster than some traditional OOPL dispatches. I claim inlining or other "customization" techniques are necessary to make OOPLs sufficiently efficient to attract mainstream programming use. If C++ has a weakness in "efficiency" it is that under some situations trivial class derivations making slight changes in virtual functions requires entirely new dispatch tables for a class be created. Thus, if C++ classes typically inherit hundreds on virtual functions, but only slightly modify one or two of those inherited functions, then the size costs of the dispatch tables can become expensive. Still, this is not a restriction of C++, but rather of current compiler implementations. Alternative compiler approaches could avoid the large dispatch table costs even in these infrequent situations. |I also have considerable problem with C++ in that given an instance one |cannot know its class at run-time. In my view this means that the object |is in some sense not truly first class and posseses only a partial identity. |Among other problems this totally blows away encapsulation in that the |behavior of the object and indeed any metalevel information is known only |to the compiler. Even within cfront this information is never explicitly |present from what I have seen. C++ instances are really only data structures |with most of their knowledge not present at all within running programs. They |are not objects in the sense that they have knowledge present within themselves |(or their class) of their own structure or behavior. They literally do not |know what they are. I counter-claim that C++ objects do know what they are, they just aren't currently allowed to tell you. :-) The reason for this is that when programmers can find out an object's type, so many programmers write bad code depending on an object's type, thus destroying code reuse. I for one, am lobbying for allowing C++ objects tell you somethings about itself. It would then be up to programmers whether they choose to write bad code or not. I do agree with you that C++ objects do have some identity weaknesses when using multiple inheritence. It would not be hard to fix such weaknesses along with allowing objects to report some run-time type information about themselves.
tma@m5.COM (Tim Atkins) (03/23/91)
In article <11550@pasteur.Berkeley.EDU> jbuck@galileo.berkeley.edu (Joe Buck) writes: > >Perhaps an implementation could be written this way, but both cfront and g++ >use only a single pointer per object, regardless of its class hierarchy. Joe, You quite simply do not know what you are talking about when it comes to cfront. I haven't tried g++ to check your contention there. - Tim
tma@m5.COM (Tim Atkins) (03/23/91)
In article <1991Mar2.052423.3231@objy.com> peter@objy.com writes: >In article <4578@m5.COM>, tma@m5.COM (Tim Atkins) writes: >|> I fail to understand the phrase "minimal object overhead" regarding >|> C++. Surely such can not be claimed in terms of space. If one cares >|> about issues of polymorphism for a given set of classes then each instance >|> will contain an overhead of at least a 4 byte virtual table pointer for >|> every class in its inheritance hierarchy than defines virtual functions. > >You are mistaking features of one particular implementation of C++ with >features of the language itself. Virtual tables (vtbls for short) ARE >NOT PART OF THE LANGUAGE. They are merely one way of implementing the >virtual function behavior of the language. True enough. I am not mistaken implementation for language however. I am merely referring to the nearest thing to a "standard" we have today, namely Cfront from ATT. Unless things have changed radically in later versions what I wrote also applies to g++, as I remember it. These two implementations unfortunately seem to cover the majority of workstation users I find posts from on comp.lang.c++ . I'm not sure about how Borland or Zortech do things or other companies do things. I would be very pleased if someone would enlighten me on alternate strategies that are *market realities*. It is no big challenge merely to think of alternate stratgies. > >Secondly, the particular implementation you are probably refering to, >cfront from ATT, does NOT have a vtbl pointer for every super class >that has virtual functions. In the single inheritance case, there is >atmost one vtbl pointer no matter how many classes in the inheritance >chain have virtual functions. Multiple inheritance is more >complicated. False, or at best only partially correct. Pre version 2.0 when there was no MI you are correct. After 2.0 even hierarchies with no multiple inheritance will have multiple vtbl pointers, one for each class in the hierarchy that defines new virtual functions. > >|> Due to the way MI is implemented in relation to >|> the implementation requirement that all superclass variables be contiquous, >|> it is quite possible that there is duplication of entire substructures >|> in the C++ instance. > >Again, this is NOT A CHARACTERISTIC of the langauge. The people at Tau Metric >and Oregon Software would probably be glad to tell you about how their compiler >doesn't make any redundant copies of base classes. I would love to hear more about how these and other companies do things. But do note that I did not say these latter things are language features. I specifically tied it to particular implementation practices in at least two places shown in the quoted material. - Tim Atkins