Topic: Language extensions for run-time type identification
Author: tmb@arolla.idiap.ch (Thomas M. Breuel)
Date: 14 Aug 92 16:54:47 GMT Raw View
In article <1992Jul26.014223.6153@uunet.uu.net!mole-end> mat@uunet.uu.net!mole-end writes:
How about this:
[1] Derivation is only useful when used properly with virtualization.
[2] Virtualization is only meaningful in the context of derivation.
[3] Only derivation can make use of RTTI.
therefore
RTTI is only useful in the presence of virtualization.
All your premises are wrong.
(1) To the limited extent that derivation is useful at all,
derivation is useful for reuse of functionality even in the
absence of virtual functions. I use derivation in C++ more
frequently than virtual functions. Other languages (Oberon,
CommonLisp DEFSTRUCT, SML) offer derivation without
virtualization.
(2) It does make sense to "virtualize" without derivation: you get
something similar to overloading in C++, except that the
"overloading" is resolved at runtime. There needs to be no
inheritance relationship among the types participating in this.
Among others, CLOS lets you do this.
(3) Users of Lisp and similar languages have made use of RTTI since
before derivation even became a concept in programming languages.
The limitations C++ has in all these areas are consequences of
its heritage and the desire to have low-overhead implementations. But
please let us not re-define reality to fit the special circumstances
of the C++ programming language.
Thomas.
Author: maxtal@extro.ucc.su.OZ.AU (John MAX Skaller)
Date: Thu, 30 Jul 1992 16:38:21 GMT Raw View
In article <1992Jul28.094428.15393@uunet.uu.net!mole-end> mat@uunet.uu.net!mole-end writes:
>
>> > Only derivation can make use of RTTI.
>
>> I disagree. Derivation needs RTTI does not mean that only derivation needs
>> RTTI. Parameterization needs RTTI too (of cause, it is not the C++ template).
>
>RTTI is only needed when an object can have an apparent type and an actual
>type. In C++, that requires derivation.
Not so. RTTI could easily be useful for distinguishing between
unrelated types.
In fact, these type *might* have a base in common, but the
is not relevant.
Consider the syntax
f(X[Y,Z]*);
which is taken to mean a pointer to X, with downcasting to Y and Z
allowed. If we allow,
f([Y,Z]*);
then it is much the same, except that there is no 'default' type,
and the argument cannot be used directly.
One can easily see how this can be used to implement a Lisp system:
typdef [float,int,string] atom;
class node {
node *CAR;
[node, atom]* CDR;
};
The notion is equivalent to a pascal variant record with run-time
checking on the discriminant.
In the case above, tagged pointers may have to be used.
When there is a common base with a virtual member, RTTI in the object
can be used instead. But that is an compiler implementation detail.
--
;----------------------------------------------------------------------
JOHN (MAX) SKALLER, maxtal@extro.ucc.su.oz.au
Maxtal Pty Ltd, 6 MacKay St ASHFIELD, NSW 2131, AUSTRALIA
;--------------- SCIENTIFIC AND ENGINEERING SOFTWARE ------------------
Author: maxtal@extro.ucc.su.OZ.AU (John MAX Skaller)
Date: Sat, 1 Aug 1992 08:39:30 GMT Raw View
In article <1992Jul29.192054.22533@cadsun.corp.mot.com> shang@corp.mot.com writes:
>In article <BryFLI.Hz2@world.std.com> wmm@world.std.com (William M Miller)
>writes:
>
>> There are only two ways to "lose" the exact type in C++ (apart from
>> explicit casting to an unrelated type, for instance): conversion of a
>> pointer/reference to a derived class into a pointer/reference to a
>> base class, and conversion to void*.
>>
>Also True, but only within a domestic environment.
Technically, it is ALWAYS true I think. At present.
The void* case IS the non-domestic case.
(Although some systems use char*).
It represents raw memory, anything else is *already* typed.
>
>> Doing something about the latter
>> is either very expensive or requires breaking compatibility with C
>> void* pointers (tagged pointers),
>>
Oh? If you assume that the void* points to an object,
and the vtbl pointer is at the low memory of the object,
then you can extract RTTI from a void* just like any other.
[If your assumptions are wrong, system crash. Same as for ANY
conversion from void*]
>True, if you do not relate the void* to the tagged pointer. Only those
>polymorphic pointers need to be tagged. void* is not a polymorphic pointer. If
>we want an equivalent polymorphic pointer, we can introduce a new one:
>anytype*, where anytype is supposed to be the root of class hierarchy. You get
>penalty only when you use it.
Please note you use the word 'hearchy'. Classes in C++
should NOT be organised as a heirarchy. That is Smalltalk style.
C++ has multiple inheritance. In most cases you can use it
*instead* of RTTI.
>
>> so realistically we are talking
>> about a requirement for RTTI that *only* has to deal with the results
>> of derived-to-base conversions.
>>
>Not exactly. It is true within a domestic environment.
No, not even then. For a heterogenous collection, it
doesn't make a lot of difference whether the objects in the collection
have a common base or not.
>
>> The question, then, is under what circumstances do such conversions
>> occur? The premise of the current proposal is that you don't *do*
>> such conversions unless you have provided for polymorphic behavior,
>> i.e., virtual functions. Inheritance for factoring and sharing of
>> representation and code is fine, but in such applications you
>> typically don't rely on derived-to-base conversions.
Well, I DO downcasting ( :-)) in my LIST class.
The link object does not have any virtual functions. The object
derived from it (in the template class) needn't have any virtual
functions either.
[Oh, and I think my design is flawed!]
>>
>Not entirely true even for a domestic system:
>
>I often have a class hierachy in which the base methods manipulate only on the
>part of the base data and no virtualization is required. All the specific
>operations in the derived classes will be performed from the specific
>interfaces. But I still need a general interface that manipultes all of the
>object at the base level. Virtual functions can help a lot in reducing the
>neccessity of downcast and hence the need of RTTI. But virtual function does
>not always help. Sometimes the specific interfaces and requirements can vary
>greatly in derived classes, it is impossible to exract a common interface as a
>virtual interface. In this case, I have to use RTTI rather than the virtual
>function.
You also might question WHY the objects are organised in a single
collection when you need to access them separately.
We have agreed that this may be forced on you in a foreign
system.
In a domestic system it is NEVER necessary. It is ALWAYS
possible to do it otherwise.
A simple technique is to emulate tagged pointers.
Then you can SELECT the pointer of your choice, without downcasting.
Another technique is to keep track of base/derived class pointer
pairs for each type. Then you can search for the base pointer, and
get the associated derived pointer.
THESE TECHNIQUES ARE CLUMBSY. So I agree using RTTI to
implement something equivalent would be a good idea.
THESE TECHNIQUES ARE NOT EQUIVALENT TO UNCONSTRAINED DOWNCASTING.
So I do not agree you should just be able to check the type of any pointer.
>
>> The challenge, then, for those who view RTTI-via-vtable as
>> insufficient is to provide *concrete* counterexamples to this
>> assumption: applications where derived-to-base casting does occur
>> without the need for virtual functions and for which RTTI would
>> nevertheless be useful. Are there such applications?
>>
>Yes.
Agreed. My list class.
>
>I can maintain a group of passive objects without intrinsic behavioral
>characteristics, needless to say any virtual functions. What I am concerned is
>only the internal data structure. These objects are usually used to carry the
>information and to be transfered between different environments. I need RTTI to
>represent or transform these objects correctly.
>For example, to transform an
>integer in an object from Intel 8086 form to network form. Although a simple
>type id is usually insufficient for this case, but it provides a key to access
>the detail type information in some type library generated by the compiler (I
>just hate to see the game of waste: inventing one precompiler after another).
>
>My multitasking system can also have an interface that take an object as input
>from other task. Such object is not necessarily virtualized. Such type check is
>usaually performed at run time. Without RTTI, my task may corrupt due to a
>wrong input type. Without language supported RTTI, I have to provide my own
>RTTI to solve this problem. If the system is general purposed and must be
>integrated with the language environment, again, I have to write a precompiler
>to create my own language (example: IDL for remote procedure call)!
>
>And I'm sure many OO database and OS people can tell more.
This is a requirement for a foreign interface. Such systems
have much higher demands on RTTI than merely knowing the type.
A proper OO database for example should be able to construct
a new user defined type AT RUN-TIME. And it should be able to sort
user objects without access to the user program that created them.
That implies storing the actual methods on disk.
>
>Since OO technique is aimed mainly to developing large, complex and
>coorperative systems, C++, as general purposed OO language, should at least
>cover some main application areas.
Lets call this XRTTI. Lets keep the initial discussions to DRTTI
(domestically usefule RTTI).
The reason for distinguishing them should be clear: DRTTI should
be constrained to be sound, maintaining the open/closed principle,
information hiding, etc.
XRTTI necessarily breaks the static type system---it must, because
it is used to impement dynamism beyond the scope of a statically
type-sound system like C++.
>
>David Shang
So perhaps our points of view are slowly converging?
--
;----------------------------------------------------------------------
JOHN (MAX) SKALLER, maxtal@extro.ucc.su.oz.au
Maxtal Pty Ltd, 6 MacKay St ASHFIELD, NSW 2131, AUSTRALIA
;--------------- SCIENTIFIC AND ENGINEERING SOFTWARE ------------------
Author: jrobie@netmbx.netmbx.de (Jonathan Robie)
Date: Tue, 21 Jul 1992 10:34:36 GMT Raw View
pathak@mitre.org (Heeren Pathak) writes:
>In article <EY048MK@netmbx.netmbx.de>, jrobie@netmbx.netmbx.de (Jonathan
>Robie) wrote:
>>
>> shang@corp.mot.com (David (Lujun) Shang) writes:
>>
>> >The language should provide run time type checking as well as array bounds
>> >checking. You can also have a switch to turn off them if you like to.
>> >
>>
>> It may be important for compilers to provide such a switch since the
>> memory overhead needed to store type information for all classes can
>> be significant. Pragmas would be necessary to switch it on and off
>> since you might need it for some classes but not for others....messy,
>> isn't it?
>>
>Why not use MI to provide a "standard" mix-in class that provides run-time
>identification?
I assume you mean that this class would give access to the run-time
identification provided by the compiler, right? That might make sense,
but I don't like the idea of making the compiler look at the derivation
tree to see whether it should generate run time identification.
Obviously, no class is going to be able to generate run time identification
for objects including it or derived from it. How should it know the
relevant types?
Jonathan
===========================================================================
Jonathan Robie jrobie@netmbx.UUCP
Arnold-Zweig-Str. 44 jrobie@netmbx.in-berlin.de
O-1100 Berlin
Deutschland Phone: +37 (2) 472 04 19 (Home, East Berlin)
+49 (30) 342 30 66 (Work, West Berlin)
--
Jonathan
===========================================================================
Author: shang@corp.mot.com (David (Lujun) Shang)
Date: Tue, 21 Jul 92 14:31:31 GMT Raw View
In article <14ft2uINNjh4@agate.berkeley.edu> jbuck@forney.berkeley.edu (Joe
Buck) writes:
> * the virtual impossibility of designing a more general solution that does
> not break compatibility with C structs (a requirement that may be
> meaningless to theoretical folks but that is nevertheless vital).
> This constraint forbids adding any data to the object of any kind.
>
The object code does not necessarily include any code about the type
information. Encoding vtable references into object code is a particular way
applied by the current C++ implementation. For a complete solution to run time
type check, this technique must be changed. I've mentioned several times, the
"tagged pointer" technique is the proper way to achieve this goal. Only those
polymorphic pointers need to be tagged (not all pointers). The tagged pointer
is not an overhead since it already eliminates the necessity to tag an object.
> * the fact that it is trivial to force any class for which run-time type
> identification is needed to have a virtual function table (simply add
> a virtual destructor).
>
Adding something virtual just for the purpose that has nothing to do with it?
> In most implementations of classes with virtual functions, each object
> already has, in effect, a type-ID: the pointer to the virtual function
> table. This is a natural hook on which to hang run time type checking.
>
The pointer to vtable can not work as a type-ID for a language with multiple
inheritance. An object of particular class derived from multiple bases may
contain serveral different vtable references. Different base pointers to the
same object may use different vtable pointers.
> I could also argue the other way: for a debugger, it isn't enough to
> identify all class objects. I also need to be able to identify the
> types of any int, double, pointer, or reference variables. There's no
> inherent reason why being able to identify all classes, but no other
> variable types, is a more natural or useful division that just being
> able to identify objects that have virtual functions.
>
I fully agree with you when you argue the other way. In fact, it is possible
and practicable to identify any types and classes, no panelty on object codes,
especially for those objects of conventional C types. The only panelty is an
additinal integer (used as internal type identifier) for each type or class.
But we can benefit a lot: integrating conventional C types into class hierarchy
without additional overhead, explicit run time type check to prevent all the
type error at compile time, type-safe cast, to solve problem with "sizeof"
operator, problem with pointer increasement and decreasement, problems with
covariant type in derived classes, and many many other interesting things.
David Shang
Author: steve@taumet.com (Steve Clamage)
Date: Tue, 21 Jul 1992 16:27:00 GMT Raw View
jbuck@forney.berkeley.edu (Joe Buck) writes:
>* the fact that it is trivial to force any class for which run-time type
> identification is needed to have a virtual function table (simply add
> a virtual destructor).
Right.
In cases where you don't want a virtual destructor, you can add a
dummy do-nothing function. This will force the creation of a
virtual table without adding any run-time code to object destruction.
class base {
...
protected:
virtual void no_op(){};
};
--
Steve Clamage, TauMetric Corp, steve@taumet.com
Vice Chair, ANSI C++ Committee, X3J16
Author: clark%asylum.cs.utah.edu@cs.utah.edu (Charles Clark)
Date: 21 Jul 92 13:55:37 MDT Raw View
In article <1992Jul21.143131.6902@cadsun.corp.mot.com> shang@corp.mot.com writes:
>In article <14ft2uINNjh4@agate.berkeley.edu> jbuck@forney.berkeley.edu (Joe
>Buck) writes:
>> * the fact that it is trivial to force any class for which run-time type
>> identification is needed to have a virtual function table (simply add
>> a virtual destructor).
>>
>Adding something virtual just for the purpose that has nothing to do with it?
I agree, forcing the programmer to add a virtual destructor (or any virtual
function) to the design of his/her classes (so the resulting vtable can
be used for type id) is dubious. Unfortunately, a programmer without access
to a a C++ compiler which provides run-time type id can do no better.
>> In most implementations of classes with virtual functions, each object
>> already has, in effect, a type-ID: the pointer to the virtual function
>> table. This is a natural hook on which to hang run time type checking.
>>
>The pointer to vtable can not work as a type-ID for a language with multiple
>inheritance. An object of particular class derived from multiple bases may
>contain serveral different vtable references. Different base pointers to the
>same object may use different vtable pointers.
Indeed. The above scheme fails when vtables are shared between base and
derived classes. This sharing occurs when using multiple inheritance
(or virtual base classes) and no inherited methods from one of the base
classes are redefined. A cast to that base, and reference to the vtable, will
yield the (shared) base vtable. Ooops, wrong type id...
Note that this is a compiler implementation detail -- an optimization that
C++ compilers use to reduce the number of vtables generated. One could
modify the compiler to not make this optimization and generate fresh vtables
for the base portions of derived classes. Now, if you've got your heart set
on run-time type id and you're prepared to modify the compiler, there is
no point in forcing the programmer to write useless virtual functions so
that a vtable will be generated. The compiler can be modified to always
generate a vtable (although it may sometimes be empty).
The overhead of doing this is one word per instance of a class that would
not normally have a vtable (plus the extra vtables).
--Charles (clark@cs.utah.edu)
Author: wmm@world.std.com (William M Miller)
Date: 21 Jul 92 20:42:59 GMT Raw View
In article <14ft2uINNjh4@agate.berkeley.edu>, Joe Buck writes:
> * the virtual impossibility of designing a more general solution that does
> not break compatibility with C structs (a requirement that may be
> meaningless to theoretical folks but that is nevertheless vital).
> This constraint forbids adding any data to the object of any kind.
I presented such a solution in my position paper on runtime type
information given in a technical session at the March, 1991 X3J16
meeting. It is somewhat more costly in time and space than the vtable
approach, so it would probably require as a practical matter that both
mechanisms be implemented, fast for classes with virtual functions and
slow(er) for other classes.
The issue is whether complete generality is sufficient justification
for complicating the implementation and adding some runtime expense
(which would be present even in programs that did not use RTTI
facilities, unless turned off by command line or #pragma). I assume
from the fact that my suggestion was not adopted into the current
proposals that the general consensus was that complete generality was
not sufficient justification. I don't know how to evaluate the
relative importance of these factors.
> I could also argue the other way: for a debugger, it isn't enough to
> identify all class objects. I also need to be able to identify the
> types of any int, double, pointer, or reference variables.
This also turns out not to be terribly difficult. Again, the issue is
trading off utility versus cost.
-- William M. Miller, wmm@world.std.com
Author: jrobie@netmbx.netmbx.de (Jonathan Robie)
Date: Wed, 22 Jul 1992 07:33:27 GMT Raw View
pathak@mitre.org (Heeren Pathak) writes:
>Well, if the complier uses the class tree when it determines the type, it
>can generate "proper" run-time id for all objects in the tree. That is I
>suggest that people look at using MI instead of pragmas.
Compilation options and derivation are two separate issues, and I would
like them to stay separate.
Jonathan
===========================================================================
Jonathan Robie jrobie@netmbx.UUCP
Arnold-Zweig-Str. 44 jrobie@netmbx.in-berlin.de
O-1100 Berlin
Deutschland Phone: +37 (2) 472 04 19 (Home, East Berlin)
+49 (30) 342 30 66 (Work, West Berlin)
--
Jonathan
===========================================================================
Author: mat@mole-end
Date: Tue, 21 Jul 1992 09:42:04 GMT Raw View
In article <1992Jul20.220534.1365@cadsun.corp.mot.com>, shang@corp.mot.com (David (Lujun) Shang) writes:
> I sencond this. As I already said, run time type checking of classes
> only with virtual functions is not a serious solution.
> David Shang
Let's be sure that we are talking about the same thing, then I'll ask you
to refute an assumption underlying the current proposal.
The current proposal would allow a number of things, including at least
checked downcasting and some kind of comparison-for-equality of the exact
type of objects.
There are many bad uses for these facilities, but there are also good
uses, or so it is believed.
The assumption underlying the decision to include only classes with
virtual functions is that a class that has no polymorphic behavior
whatsoever (not even a virtual destructor) cannot be used in any way
that is both safe and interesting even with the proposed runtime type
support. Can you refute this assumption?
--
(This man's opinions are his own.)
From mole-end Mark Terribile
uunet!mole-end!mat, Somewhere in Matawan, NJ
Author: shang@corp.mot.com (David (Lujun) Shang)
Date: Wed, 22 Jul 92 15:03:30 GMT Raw View
In article <1992Jul21.094204.20100@mole-end> mat@mole-end writes:
>
> The assumption underlying the decision to include only classes with
> virtual functions is that a class that has no polymorphic behavior
> whatsoever (not even a virtual destructor) cannot be used in any way
> that is both safe and interesting even with the proposed runtime type
> support. Can you refute this assumption?
> --
Yes.
First of all and to be specific to C++, it is the class hierarchy, or
inheritance and the polymorphic pointers that lead to the necessity of run time
type checking. It is not the virtual behaviors of a class. We still need run
time type check even if we disallow any virtual behaviors in C++. Therefore,
the assumption is laid on the wrong ground. I can only accept this assumption:
run time type check is not necessary for any argument that is sepcified by a
sealed class or that is sealed itself. Here "sealed" means "no derived" or
"cannot be used to derive".
Secondly, the real reason to limit the current proposal to classes only with
virtual behaviors is not that classes without virtual behaviors are not
necessary to be run time type checked. The real reason is an
implementation-dependent issue: classes with virtual functions have vtables
which can be used to store the run time type info, and it is impossible to
create a vtable or some equivalent for each class or even the conventional C
type since this would require each object to carry an overhead, even a simple
integer or a character. This problem is cuased by the limit of the current C++
implementation, not by the C++ language itself. We do have a proper
implementation alternative as applied in other strongly-typed OO langauges that
can support a complete run time type check. My question is: why should we add
an imperfect language concept that is limited by the current implementation?
David Shang
Author: bobm@Ingres.COM (Bob McQueer)
Date: 22 Jul 92 17:30:19 GMT Raw View
In <14ft2uINNjh4@agate.berkeley.edu>,
dated 21 Jul 92 02:34:06 GMT,
jbuck@forney.berkeley.edu (Joe Buck) writes:
> In most implementations of classes with virtual functions, each object
> already has, in effect, a type-ID: the pointer to the virtual function
> table. This is a natural hook on which to hang run time type checking.
I think Mr. Buck has hit the nail on the head here. I've been meaning to ask
about this myself, and was happy to see this discussion thread start. The
virtual function table exists as a 1-per-class structure, and is the natural
place to insert other runtime class information without replicating anything.
The reasonable overhead on each object instantiation would be 1 pointer to
the virtual function table, which we might want to start calling a class
descriptor, or something like that.
I think we have to recognize that C++ is not a purist's OO language - it
is a way of adding OO functionality to an existing language. Its strength
lies in being able to use an OO paradigm, while still retaining the
efficiency of C, and having "escape hatches". Insisting that only certain
classes can have runtime descriptors seems reasonable, given this intent.
What I was going to ask about was actually support for an "isa" operation,
which requires some type of runtime definition. Yes, this type of thing can
be abused, but it is definitely useful. It should NOT be used as a substitute
for proper subclassing and definition of virtual functions, but I think it
is needed.
Another aspect - if we have the ability to get at class descriptors, can there
be an extension which allows them to be used with the "new" operator to
parameterize the class of object being allocated. I think that as "service"
classes begin to be provided, it might be handy. Think in terms of C++
application generators which generate the code to manipulate certain classes of
objects, which may be customized by allowing the user to subclass the basic
types.
Author: rmartin@thor.Rational.COM (Bob Martin)
Date: 22 Jul 92 18:19:20 GMT Raw View
shang@corp.mot.com (David (Lujun) Shang) writes:
|In article <14ft2uINNjh4@agate.berkeley.edu> jbuck@forney.berkeley.edu (Joe
|Buck) writes:
|
|> * the fact that it is trivial to force any class for which run-time type
|> identification is needed to have a virtual function table (simply add
|> a virtual destructor).
|>
|Adding something virtual just for the purpose that has nothing to do with it?
Posh! Every class should have a virtual destructor. It is insane not
to declare the destructor virtual. There is only one, small,
exception to this rule, which has to do with structs placed in ROM...
--
+---Robert C. Martin---+-RRR---CCC-M-----M-| R.C.M. Consulting |
| rmartin@rational.com |-R--R-C----M-M-M-M-| C++/C/Unix Engineering |
| (Uncle Bob.) |-RRR--C----M--M--M-| OOA/OOD/OOP Training |
+----------------------+-R--R--CCC-M-----M-| Product Design & Devel. |
Author: mat@mole-end
Date: Wed, 22 Jul 1992 09:17:52 GMT Raw View
Just a point of fact:
In article <1992Jul21.143131.6902@cadsun.corp.mot.com>, shang@corp.mot.com (David (Lujun) Shang) writes:
> > In most implementations of classes with virtual functions, each object
> > already has, in effect, a type-ID: the pointer to the virtual function
> > table. This is a natural hook on which to hang run time type checking.
> The pointer to vtable can not work as a type-ID for a language with multiple
> inheritance. An object of particular class derived from multiple bases may
> contain serveral different vtable references. Different base pointers to the
> same object may use different vtable pointers.
Not quite true. Those multiple vtable references in a complete object
all have to point to vtables whose only differences are their `offset
adjustments.'
This area has been studied to death and is being studied right now into
the twilight zone and while some problems remain, this is not one of them.
--
(This man's opinions are his own.)
From mole-end Mark Terribile
uunet!mole-end!mat, Somewhere in Matawan, NJ
Author: shang@corp.mot.com (David (Lujun) Shang)
Date: Thu, 23 Jul 92 13:45:15 GMT Raw View
In article <1992Jul21.143131.6902@cadsun.corp.mot.com>, shang@corp.mot.com
(David (Lujun) Shang) writes:
> The pointer to vtable can not work as a type-ID for a language with multiple
> inheritance. An object of particular class derived from multiple bases may
> contain serveral different vtable references. Different base pointers to the
> same object may use different vtable pointers.
NoIn article <1992Jul22.091752.22521@mole-end> mat@mole-end writes:
> Just a point of fact:
> Not quite true. Those multiple vtable references in a complete object
> all have to point to vtables whose only differences are their `offset
> adjustments.'
>
Good point! To compare two types then can be done by comparing the segment or
page number of two vtables. The penalty is only for those C++ implemented in
16-bit environment. The vtable reference cannot be a 16-bit pointer for small
programs.
David Shang
Author: maxtal@extro.ucc.su.OZ.AU (John MAX Skaller)
Date: Thu, 23 Jul 1992 17:41:58 GMT Raw View
In article <1992Jul21.094204.20100@mole-end> mat@mole-end writes:
>In article <1992Jul20.220534.1365@cadsun.corp.mot.com>, shang@corp.mot.com (David (Lujun) Shang) writes:
>
>> I sencond this. As I already said, run time type checking of classes
>> only with virtual functions is not a serious solution.
>
>> David Shang
>
>Let's be sure that we are talking about the same thing, then I'll ask you
>to refute an assumption underlying the current proposal.
>
>The current proposal would allow a number of things, including at least
>checked downcasting and some kind of comparison-for-equality of the exact
>type of objects.
>
>There are many bad uses for these facilities, but there are also good
>uses, or so it is believed.
>
>The assumption underlying the decision to include only classes with
>virtual functions is that a class that has no polymorphic behavior
>whatsoever (not even a virtual destructor) cannot be used in any way
>that is both safe and interesting even with the proposed runtime type
>support. Can you refute this assumption?
>--
Before I start: I'm not against adding RTTI. But allow
me to play 'devils advocate' as hard as I can. :-) Convince
me that downcasting is a good thing, for example.
What is the basis for this assumption?
On the contrary, polymorphism BY NATURE, provides the
correct mechanism for accessing the exact object, it is
especially in this case that casting is not only dangerous
but unnecessary.
In the discussion about RTTI I have participated in with David,
we agree on at least one thing: RTTI is required for writing Debugger.
Clearly a debugger needs access to ALL the type information,
so mere safe downcasting and comparison for equality would not be
adequate, nor a restriction to classes with virtual functions.
I think precisly the same argument applies to, say,
an OO database or any other facility for porting/storing, or
accessing objects. Here enough information is required
to construct objects in the media/user interface.
Using a classification scheme suggested by David, I will
call the systems requiring external access *foreign* systems,
and the debugger is what I might call a *meta* system.
In any case the RTTI proposal above will not adequately
support these types of systems, although it might aid in their design.
That leaves what might be called *domestic* systems,
your common garden program for doing matrix algebra, parsing
a language, etc. These systems include the bulk of operating
systems and other things too.
It is my belief that DOWNCASTING in such domestic systems
is never necessary. In such systems your program creates
all the objects, therefore, at the point the object is created
it knows the exact type of the objects.
It is always possible, I contend, to preserve that type
information if it will be required later. If it is thrown away,
the information is deliberately lost specifically to prevent
the object from being accessed with knowledge of its type.
For example, if I have an abstract class A, and
a subroutine returns a pointer to A, then the subroutine
is deliberately coded so that the true type of the object
cannot be known. That gives me freedom to change the implementation,
knowing for sure nothing can depend on the actual type of the object.
Everthing depends only on the interface specified in the abstract class.
If that pointer can be cast, whether safely or not,
whether by RTTI or not, to a derived type, then the
implied encapsulation of the OPEN/CLOSED principle is destroyed.
That is, not only is the private implementation of a base class
hidden, but also all the details of all derived types are hidden,
and for the same reason: they are allowed to be changed.
In the case of downcasting it is much more serious than
accessing implementation details: this does not require
change of the private section, but merely the existence
of several derived classes.
The correct way to view RTTI then, is not to
support downcasting, but ANY casting, including and
especially casting from a void* to any class at all.
As such, there is no reason that I can see that
such casts would be 'interesting' only when there is
by chance a base with a virtual function, since
in that case casting (downcasting) is especially bad style.
[Never-the-less, if we're going to downcast,
it should be at least *possible* for virtual bases.]
There is probably a similar argument for
comparison for equality, or, better, comparison
to see if one class is heir to another, however in this
case the use of RTTI might be more essential,
since it facilitates binary operators acting
on two objects of the same type, a poor mans
version of multi-methods or safe covariant
parameters.
In summary: the proposal above does not go
far enough to support those genuine uses of RTTI in foreign
or meta systems, and attempts to support casting in domestic
systems where it is not only not required, but actually
invalidates the rationale of class based programming,
namely the open/closed principle.
--
;----------------------------------------------------------------------
JOHN (MAX) SKALLER, maxtal@extro.ucc.su.oz.au
Maxtal Pty Ltd, 6 MacKay St ASHFIELD, NSW 2131, AUSTRALIA
;--------------- SCIENTIFIC AND ENGINEERING SOFTWARE ------------------
Author: maxtal@extro.ucc.su.OZ.AU (John MAX Skaller)
Date: Thu, 23 Jul 1992 20:08:03 GMT Raw View
In article <1992Jul22.212111.12530@taumet.com> steve@taumet.com (Steve Clamage) writes:
>
>We could patch this up by saying you have to use 'class' rather than
>'struct' to get RTTI, but this would break existing C++ code which
>relies on the equivalence of 'struct' and 'class'. Maybe this is
>not too high a penalty, but it would have to be carefully considered.
IMHO making struct == class (baring access defaults) was a poor
decision. I would much rather 'struct' MEANT C-compatible.
So I would not be dismayed at the change suggested above.
--
;----------------------------------------------------------------------
JOHN (MAX) SKALLER, maxtal@extro.ucc.su.oz.au
Maxtal Pty Ltd, 6 MacKay St ASHFIELD, NSW 2131, AUSTRALIA
;--------------- SCIENTIFIC AND ENGINEERING SOFTWARE ------------------
Author: mat@uunet.uu.net!mole-end
Date: Thu, 23 Jul 1992 18:30:41 GMT Raw View
In article <1992Jul22.150330.6160@cadsun.corp.mot.com>, shang@corp.mot.com (David (Lujun) Shang) writes:
> In article <1992Jul21.094204.20100@mole-end> mat@mole-end writes:
> >
> > The assumption underlying the decision to include only classes with
> > virtual functions is that a class that has no polymorphic behavior
> > whatsoever (not even a virtual destructor) cannot be used in any way
> > that is both safe and interesting even with the proposed runtime type
> > support. Can you refute this assumption?
> > --
> First of all and to be specific to C++, it is the class hierarchy, or
> inheritance and the polymorphic pointers that lead to the necessity of
> run time type checking. It is not the virtual behaviors of a class.
> We still need run time type check even if we disallow any virtual behaviors
> in C++. Therefore, the assumption is laid on the wrong ground.
But without virtualization (polymorphic behavior) derivation is effectively
useless. There is no reason to code inheritance without providing for
virtualization. Then the case which you mention is of no use unless and
until it is provided with RTTI; providing RTTI for it using reasonable
and economical mechanisms would violate certain assumptions that C++ allows
its users to make (C struct compatability).
--
(This man's opinions are his own.)
From mole-end Mark Terribile
uunet!mole-end!mat, Somewhere in Matawan, NJ
Author: mat@uunet.uu.net!mole-end
Date: Fri, 24 Jul 1992 07:03:25 GMT Raw View
In article <1992Jul23.134515.12794@cadsun.corp.mot.com>, shang@corp.mot.com (David (Lujun) Shang) writes:
> In article <1992Jul21.143131.6902@cadsun.corp.mot.com>, shang@corp.mot.com
> (David (Lujun) Shang) writes:
> > The pointer to vtable can not work as a type-ID for a language with
> > multiple inheritance. An object of particular class derived from
> > multiple bases may contain serveral different vtable references.
> > Different base pointers to the same object may use different vtable
> > pointers.
> In article <1992Jul22.091752.22521@mole-end> mat@mole-end writes:
> > Just a point of fact:
> > Not quite true. Those multiple vtable references in a complete object
> > all have to point to vtables whose only differences are their `offset
> > adjustments.'
> Good point! To compare two types then can be done by comparing the segment or
> page number of two vtables. The penalty is only for those C++ implemented in
> 16-bit environment. The vtable reference cannot be a 16-bit pointer for small
> programs.
David,
Eh? I was not using `offset adjustment' in reference to a segmented memory
addressing scheme; I was using it to describe a necessary feature of a
vtable for MI: an explicit or implicit displacement by which a pointer must
be adjusted during the invocation of a virtual function.
And not to make you too happy: comparing vtable pointers could only be
a first step unless you are absolutely sure that the compilation and
linking system will never duplicate a vtable. This is a hard assumption
to prove, especially with dynamic linking of new types.
OBTW, are you a typewriter-trained touch typist? Your text has trailing
blanks on almost every line.
--
(This man's opinions are his own.)
From mole-end Mark Terribile
uunet!mole-end!mat, Somewhere in Matawan, NJ
Author: maxtal@extro.ucc.su.OZ.AU (John MAX Skaller)
Date: Fri, 24 Jul 1992 14:24:52 GMT Raw View
In article <1992Jul23.183041.147@uunet.uu.net!mole-end> mat@uunet.uu.net!mole-end writes:
>In article <1992Jul22.150330.6160@cadsun.corp.mot.com>, shang@corp.mot.com (David (Lujun) Shang) writes:
>> In article <1992Jul21.094204.20100@mole-end> mat@mole-end writes:
>> >
>> > The assumption underlying the decision to include only classes with
>> > virtual functions is that a class that has no polymorphic behavior
>> > whatsoever (not even a virtual destructor) cannot be used in any way
>> > that is both safe and interesting even with the proposed runtime type
>> > support. Can you refute this assumption?
>> > --
>
>
>> First of all and to be specific to C++, it is the class hierarchy, or
>> inheritance and the polymorphic pointers that lead to the necessity of
>> run time type checking. It is not the virtual behaviors of a class.
>> We still need run time type check even if we disallow any virtual behaviors
>> in C++. Therefore, the assumption is laid on the wrong ground.
>
>But without virtualization (polymorphic behavior) derivation is effectively
>useless. There is no reason to code inheritance without providing for
>virtualization. Then the case which you mention is of no use unless and
>until it is provided with RTTI; providing RTTI for it using reasonable
>and economical mechanisms would violate certain assumptions that C++ allows
>its users to make (C struct compatability).
But I would make that argument backwards.
One often wants het. aggregates of unrelated types.
Actually, these are aggregates of the *same* type,
namely, the union of the unrelated types.
On the otherhand, polymorphism is the mechanism by which
the derived type NEED NOT BE KNOWN. Indeed, if we are to preserve
the open/closed principle, MUST NOT BE KNOWN.
So you (well, X3) is considering using RTTI in
precisely the case it is not needed, and not supplying it
when it actually could be useful :-)
--
;----------------------------------------------------------------------
JOHN (MAX) SKALLER, maxtal@extro.ucc.su.oz.au
Maxtal Pty Ltd, 6 MacKay St ASHFIELD, NSW 2131, AUSTRALIA
;--------------- SCIENTIFIC AND ENGINEERING SOFTWARE ------------------
Author: shang@corp.mot.com (David (Lujun) Shang)
Date: Fri, 24 Jul 92 13:37:12 GMT Raw View
In article <1992Jul23.200803.22371@ucc.su.OZ.AU> maxtal@extro.ucc.su.OZ.AU
(John MAX Skaller) writes:
> IMHO making struct == class (baring access defaults) was a poor
> decision. I would much rather 'struct' MEANT C-compatible.
>
I couldn't agree more. Making struct == class brings about a big obstacle to
explore further the concept of class. Structure should not have the inheritance
hierarchy, otherwise we make a great trouble in trading off between the
C-compatible struct and the class-equivalent struct when the class concept
should be enhanced in C++.
David Shang
Author: shang@corp.mot.com (David (Lujun) Shang)
Date: Fri, 24 Jul 92 13:56:09 GMT Raw View
In article <1992Jul24.012050.6092@hellgate.utah.edu>
clark%asylum.cs.utah.edu@cs.utah.edu (Charles Clark) writes:
>
> Yes, compatibility with C structs is compromised by this scheme of
> hijacking the vtable to provide run-time type id. If you just can't
> give up on this scheme, and are determined to make it work -- no matter
> what -- here are a couple other patches to consider:
>
> (a) Modify the C compiler to provide RTTI for structs, using the same
> technique. (After modifying the C++ compiler you'll be good at this
> kind of thing... :-} ).
>
Each argument in C is specified by a unique type and a typecast in C is
definitely a cast between two different types (if we view void as a concrete
type). There for C DOES NOT need RTTI. It is not a good idea to enforce a C++
penalty to C.
> (b) Force the use of a linkage specifier for, not only C functions, but
> also C structs. No type identification would be provided for C structs
> (both C++ classes and structs would have RTTI).
>
This is not a good solution either. Within a C++ module, we should not
distinguish what is C struct, what is C++ struct, or what is C int and what is
C++ int. The only distinguish should be made is that what module is written in
C and what module is written in C++. For those module written in C, we still
can add RTTI for those types and struts contained in the head files for C++
environment IF IT IS REQUIRED (although the C programms never use RTTI).
David Shang
Author: mat@uunet.uu.net!mole-end
Date: Sat, 25 Jul 1992 07:11:25 GMT Raw View
In article <1992Jul23.200803.22371@ucc.su.OZ.AU>, maxtal@extro.ucc.su.OZ.AU (John MAX Skaller) writes:
> In article <1992Jul22.212111.12530@taumet.com> steve@taumet.com (Steve Clamage) writes:
> >We could patch this up by saying you have to use 'class' rather than
> >'struct' to get RTTI, but this would break existing C++ code which
> >relies on the equivalence of 'struct' and 'class'. Maybe this is
> >not too high a penalty, but it would have to be carefully considered.
> IMHO making struct == class (baring access defaults) was a poor
> decision. I would much rather 'struct' MEANT C-compatible.
> So I would not be dismayed at the change suggested above.
You wouldn't, but I would. That's an awfully high-priced change. And I
think that there are a few hundred million lines of C++ in the various
programs that would be affected.
--
(This man's opinions are his own.)
From mole-end Mark Terribile
uunet!mole-end!mat, Somewhere in Matawan, NJ
Author: mat@uunet.uu.net!mole-end
Date: Sat, 25 Jul 1992 07:25:22 GMT Raw View
In article <1992Jul24.142452.756@ucc.su.OZ.AU>, maxtal@extro.ucc.su.OZ.AU (John MAX Skaller) writes:
> In article <1992Jul23.183041.147@uunet.uu.net!mole-end> mat@uunet.uu.net!mole-end writes:
> >In article <1992Jul22.150330.6160@cadsun.corp.mot.com>, shang@corp.mot.com (David (Lujun) Shang) writes:
> >> In article <1992Jul21.094204.20100@mole-end> mat@mole-end writes:
[much STUFF omitted]
> >But without virtualization (polymorphic behavior) derivation is effectively
> >useless. There is no reason to code inheritance without providing for
> >virtualization. Then the case which you mention is of no use unless and
> >until it is provided with RTTI; providing RTTI for it using reasonable
> >and economical mechanisms would violate certain assumptions that C++ allows
> >its users to make (C struct compatability).
> But I would make that argument backwards.
> One often wants het. aggregates of unrelated types.
> Actually, these are aggregates of the *same* type,
> namely, the union of the unrelated types.
No, they are aggregates of objects which share some common property
represented by some base type.
A union of three types, related or unrelated, is not any of those types.
It is something else.
> On the otherhand, polymorphism is the mechanism by which
> the derived type NEED NOT BE KNOWN. Indeed, if we are to preserve
> the open/closed principle, MUST NOT BE KNOWN.
Not so, since the current RTTI proposal would not look past private
derivation.
> So you (well, X3) is considering using RTTI in
> precisely the case it is not needed, and not supplying it
> when it actually could be useful :-)
You are offering a type system error (union of A, B, and C as either
an A or a B or a C) instead of using the type system to support the
commonality deliberately programmed into the types.
(Anyone got a good intro to either classical or modern category theory?
And I don't mean the mathematical muddle on morphisms ...)
--
(This man's opinions are his own.)
From mole-end Mark Terribile
uunet!mole-end!mat, Somewhere in Matawan, NJ
Author: maxtal@extro.ucc.su.OZ.AU (John MAX Skaller)
Date: Sat, 25 Jul 1992 18:40:58 GMT Raw View
In article <1992Jul25.072522.4316@uunet.uu.net!mole-end> mat@uunet.uu.net!mole-end writes:
>In article <1992Jul24.142452.756@ucc.su.OZ.AU>, maxtal@extro.ucc.su.OZ.AU (John MAX Skaller) writes:
>> In article <1992Jul23.183041.147@uunet.uu.net!mole-end> mat@uunet.uu.net!mole-end writes:
>
>> But I would make that argument backwards.
>
>> One often wants het. aggregates of unrelated types.
>> Actually, these are aggregates of the *same* type,
>> namely, the union of the unrelated types.
>
>No, they are aggregates of objects which share some common property
>represented by some base type.
No wait, I said we often want aggregates of *unrelated* types.
You cant change that on meb and say they have a common base!
Example: aggregates of numbers, some float, some int.
There's no common base here.
Example: baskets of fruit. No common base desired.
(the baskets are just for eating, the fruits have no
properties of interest)
>
>A union of three types, related or unrelated, is not any of those types.
>It is something else.
Yes, it is the union of the types. Which is a type.
>
>> On the otherhand, polymorphism is the mechanism by which
>> the derived type NEED NOT BE KNOWN. Indeed, if we are to preserve
>> the open/closed principle, MUST NOT BE KNOWN.
>
>Not so, since the current RTTI proposal would not look past private
>derivation.
I think you are confused here (but it might be me :-)
Private derivation hides the BASE class.
A reference to a base class hides the derived class.
THAT is requires by the open/closed principle,
the derived class --- JUST LIKE THE PRIVATE part of the
base class --- is IMPLEMENTATION DETAIL and MUST BE HIDDEN
for the SAME REASONS.
>
>> So you (well, X3) is considering using RTTI in
>> precisely the case it is not needed, and not supplying it
>> when it actually could be useful :-)
>
>You are offering a type system error (union of A, B, and C as either
>an A or a B or a C) instead of using the type system to support the
>commonality deliberately programmed into the types.
But you want the type system not to support the commonality
(which it already does--thats called polymorphism )
but to support the non-common bits.
>
>(Anyone got a good intro to either classical or modern category theory?
>And I don't mean the mathematical muddle on morphisms ...)
Tis not a muddle: tis a superb theory (the mathematical one).
>--
> (This man's opinions are his own.)
> From mole-end Mark Terribile
>
> uunet!mole-end!mat, Somewhere in Matawan, NJ
--
;----------------------------------------------------------------------
JOHN (MAX) SKALLER, maxtal@extro.ucc.su.oz.au
Maxtal Pty Ltd, 6 MacKay St ASHFIELD, NSW 2131, AUSTRALIA
;--------------- SCIENTIFIC AND ENGINEERING SOFTWARE ------------------
Author: mat@uunet.uu.net!mole-end
Date: Sun, 26 Jul 1992 01:42:23 GMT Raw View
In article <1992Jul24.141611.19647@cadsun.corp.mot.com>, shang@corp.mot.com (David (Lujun) Shang) writes:
> In article <1992Jul23.183041.147@uunet.uu.net!mole-end>
> mat@uunet.uu.net!mole-end writes:
> > But without virtualization (polymorphic behavior) derivation is effectively
> > useless. There is no reason to code inheritance without providing for
> > virtualization.
> I disagree. The language Oberon ... has derivation without virtualization.
> Can you say that the derivation is useless in Oberon, or the language
> Oberon is useless since it adds only a useless thing to Module-2?
> Derivation is introduced mainly for code reuse, not for polymorphism. ...
The catch is that C++ DOES support both polymorphism and polymorphic
conversions of pointers and references. Given that the language supports
those conversions, to NOT make the proper things polymorphic is to invite
type errors.
> > Then the case which you mention is of no use unless and
> > until it is provided with RTTI; ...
> Even we suppose what you said was true, it is still against logic to get the
> conclusion that only those polymorphic classes need RTTI:
> if
> Derivation requires RTTI, and
> Derivation requires virtualization (otherwise it is useless)
> then
> Only virtualization requires RTTI
How about this:
Derivation is only useful when used properly with virtualization.
Virtualization is only meaningful in the context of derivation.
Only derivation can make use of RTTI.
therefore
RTTI is only useful in the presence of virtualization.
------------------------------------------------------------------------------
1) Every idea of mine, that cannot be expressed as a syllogism,
is really ridiculous;
2) None of my ideas about Bath-buns are worth writing down;
3) No idea of mine, that fails to come true, can be expressed as
a syllogism;
4) I never have any really ridiculous idea, that I do not at
once refer to my solicitor;
5) My dreams are all about Bath-buns;
6) I never refer any idea of mine to my solicitor, unless it
is worth writing down.
--RAH/CRD _The Number of the Beast_
--
(This man's opinions are his own.)
From mole-end Mark Terribile
uunet!mole-end!mat, Somewhere in Matawan, NJ
Author: mat@uunet.uu.net!mole-end
Date: Tue, 28 Jul 1992 09:44:28 GMT Raw View
In article <1992Jul27.173614.8320@cadsun.corp.mot.com>, shang@corp.mot.com (David (Lujun) Shang) writes:
> In article <1992Jul26.014223.6153@uunet.uu.net!mole-end>
> mat@uunet.uu.net!mole-end writes:
> > Derivation is only useful when used properly with virtualization.
> I disagree. Without virtualization, derivation is still useful in code reuse.
Usable, but unsafe.
> Virtualizaton only makes derivation more powerful in express polymorphism.
> > Virtualization is only meaningful in the context of derivation.
> I disagree. Virtualization actually is a kind of specialization. In
> addition to virtual functions, we can also have vitual types and virtual
> constants. ...
This is comp.{lang,std}.c++, not comp.object. Your paragraph does not
describe C++; it does not describe something that is C++ + <delta> . (In
comp.object, this might be an interesting journey upon which to embark.)
> > Only derivation can make use of RTTI.
> I disagree. Derivation needs RTTI does not mean that only derivation needs
> RTTI. Parameterization needs RTTI too (of cause, it is not the C++ template).
RTTI is only needed when an object can have an apparent type and an actual
type. In C++, that requires derivation. Again, these groups talk about
C++ and sometimes about stuff within a <delta> radius of C++. I believe
you are beyond that <delta>.
> > therefore
> > RTTI is only useful in the presence of virtualization.
> Since I agree to none of the assumptions, I cannot agree to the conclusion
> either.
Not even in the context of C++?
Two is not equal to three, not even for large values of two. (Grabel's Law)
--
(This man's opinions are his own.)
From mole-end Mark Terribile
uunet!mole-end!mat, Somewhere in Matawan, NJ
Author: bobm@Ingres.COM (Bob McQueer)
Date: 27 Jul 92 18:01:15 GMT Raw View
In <1992Jul24.070325.1597@uunet.uu.net!mole-end>,
dated Fri, 24 Jul 1992 07:03:25 GMT,
mat@uunet.uu.net!mole-end writes:
> And not to make you too happy: comparing vtable pointers could only be
> a first step unless you are absolutely sure that the compilation and
> linking system will never duplicate a vtable. This is a hard assumption
> to prove, especially with dynamic linking of new types.
I think it is just a first step anyway - when I want to know at run time if
an object is of a particular class, what I really want to ask is "is it this
class, or any class derived from it?", which implies somebody taking the
vtable (enhanced into class descriptor) pointer in the object instantiation,
and ascending through its parents. With multiple inheritance, there can be
several flavors of this question.
As has already been said, this sort of thing can be abused, and is not a
substitute for proper use of virtual methods, but it IS useful.
I would also like to see the ability to parameterize the type handed
to the "new" operator - logically, this thing is a class descriptor also.
Perhaps the committee ought to be considering the various sorts of "meta"
operations people want to perform which involve parameterization of or
manipulation of type information, and see if we shouldn't surface the idea
of a "class descriptor" object of some sort as a formal part of the language?
I have not been using C++ extensively, but for the past couple years I have
been using another C based OO paradigm. I have found that there are a certain
number of operations (yes, PARTICULARLY for debuggers) in which a formal idea
of a type object with appropriate methods is indispensible.
Author: shang@corp.mot.com (David (Lujun) Shang)
Date: Mon, 27 Jul 92 17:36:14 GMT Raw View
In article <1992Jul26.014223.6153@uunet.uu.net!mole-end>
mat@uunet.uu.net!mole-end writes:
>
> How about this:
>
> Derivation is only useful when used properly with virtualization.
I disagree. Without virtualization, derivation is still useful in code reuse.
Virtualizaton only makes derivation more powerful in express polymorphism.
> Virtualization is only meaningful in the context of derivation.
I disagree. Virtualization actually is a kind of specialization. In addition to
virtual functions, we can also have vitual types and virtual constants.
Therefore, virtualization is actually a kind of parameterization. If we design
class structure in this way: a class can be parameterized with a type, a
constant, and a function, then, virtualization is still meaningful and useful
without derivation.
> Only derivation can make use of RTTI.
I disagree. Derivation needs RTTI does not mean that only derivation needs
RTTI. Parameterization needs RTTI too (of cause, it is not the C++ template).
> therefore
> RTTI is only useful in the presence of virtualization.
>
Since I agree to none of the assumptions, I cannot agree to the conclusion
either.
David Shang
Author: wmm@world.std.com (William M Miller)
Date: Sat, 25 Jul 1992 17:08:05 GMT Raw View
I'd like to make a short comment about the rationale for providing
RTTI only for classes with virtual functions -- even though I
suggested what I considered to be a practical way of providing RTTI
for classes without virtual functions (not tagged pointers, BTW), I
can understand the reasoning for restricting RTTI. It's not just
convenience in piggybacking onto existing technology, although that is
an attractive aspect of the current proposal. The real question is
when RTTI is likely to be used.
Consider this: dynamic typing is only required when you've "lost" the
exact type of the object to which an expression refers. In all other
cases, the static type of the expression is sufficient, and the
compiler can just provide a direct reference to the typeinfo if the
program requests type information.
There are only two ways to "lose" the exact type in C++ (apart from
explicit casting to an unrelated type, for instance): conversion of a
pointer/reference to a derived class into a pointer/reference to a
base class, and conversion to void*. Doing something about the latter
is either very expensive or requires breaking compatibility with C
void* pointers (tagged pointers), so realistically we are talking
about a requirement for RTTI that *only* has to deal with the results
of derived-to-base conversions.
The question, then, is under what circumstances do such conversions
occur? The premise of the current proposal is that you don't *do*
such conversions unless you have provided for polymorphic behavior,
i.e., virtual functions. Inheritance for factoring and sharing of
representation and code is fine, but in such applications you
typically don't rely on derived-to-base conversions.
The challenge, then, for those who view RTTI-via-vtable as
insufficient is to provide *concrete* counterexamples to this
assumption: applications where derived-to-base casting does occur
without the need for virtual functions and for which RTTI would
nevertheless be useful. Are there such applications?
-- William M. Miller, wmm@world.std.com
Author: chased@rbbb.Eng.Sun.COM (David Chase)
Date: 28 Jul 1992 17:57:47 GMT Raw View
In article <1992Jul27.180115.1889@pony.Ingres.COM> bobm@Ingres.COM (Bob McQueer) writes:
>... when I want to know at run time if
>an object is of a particular class, what I really want to ask is "is it this
>class, or any class derived from it?", which implies somebody taking the
>vtable (enhanced into class descriptor) pointer in the object instantiation,
>and ascending through its parents. With multiple inheritance, there can be
>several flavors of this question.
Do be careful not to confuse the desired meaning of "X is a Foo" with
how it is actually implemented. For single inheritance, the best
implementation is probably not what you think it is. For multiple
inheritance, I'm not sure what the best answer is, but I can certainly
imagine a sparse representation of the (bit) matrix encoding the
relation "T1 is a T2".
David Chase
Sun
Author: bobm@Ingres.COM (Bob McQueer)
Date: 28 Jul 92 23:36:54 GMT Raw View
In <l7b2krINN10u@exodus.Eng.Sun.COM>,
dated 28 Jul 1992 17:57:47 GMT,
chased@rbbb.Eng.Sun.COM (David Chase) writes:
> >... when I want to know at run time if
> >an object is of a particular class, what I really want to ask is "is it this
> >class, or any class derived from it?", which implies somebody taking the
> >vtable (enhanced into class descriptor) pointer in the ...
>
> Do be careful not to confuse the desired meaning of "X is a Foo" with
> how it is actually implemented. For single inheritance, the best
> implementation is probably not what you think it is . ...
Point taken. You are correct. However, the question I want to ask still
stands, and a simple comparison of my vtable pointer with the pointer for
a given class isn't sufficient, which was the point I really wanted to make.
There possibly are more efficient ways to do it than to ascend through the
tree to the original base class given any underlying implementation. Again,
this underscores the need to think through this within the language definition,
rather than having everybody reimplement it in their favorite ad-hoc manner.
Author: shang@corp.mot.com (David (Lujun) Shang)
Date: Wed, 29 Jul 92 15:27:14 GMT Raw View
In article <1992Jul28.094428.15393@uunet.uu.net!mole-end>
mat@uunet.uu.net!mole-end writes:
>
> This is comp.{lang,std}.c++, not comp.object. Your paragraph does not
> describe C++; it does not describe something that is C++ + <delta> . (In
> comp.object, this might be an interesting journey upon which to embark.)
>
The basic concept of derivation and virtualization is independent to any
particular language. The assumption that only virtualization needs RTTI can not
become reasonable in C++ while it is not reasonable in other OO languages.
David Shang
Author: shang@corp.mot.com (David (Lujun) Shang)
Date: Wed, 29 Jul 92 19:20:54 GMT Raw View
In article <BryFLI.Hz2@world.std.com> wmm@world.std.com (William M Miller)
writes:
>
> Consider this: dynamic typing is only required when you've "lost" the
> exact type of the object to which an expression refers. In all other
> cases, the static type of the expression is sufficient, and the
> compiler can just provide a direct reference to the typeinfo if the
> program requests type information.
>
Definitely true.
> There are only two ways to "lose" the exact type in C++ (apart from
> explicit casting to an unrelated type, for instance): conversion of a
> pointer/reference to a derived class into a pointer/reference to a
> base class, and conversion to void*.
>
Also True, but only within a domestic environment.
> Doing something about the latter
> is either very expensive or requires breaking compatibility with C
> void* pointers (tagged pointers),
>
True, if you do not relate the void* to the tagged pointer. Only those
polymorphic pointers need to be tagged. void* is not a polymorphic pointer. If
we want an equivalent polymorphic pointer, we can introduce a new one:
anytype*, where anytype is supposed to be the root of class hierarchy. You get
penalty only when you use it.
> so realistically we are talking
> about a requirement for RTTI that *only* has to deal with the results
> of derived-to-base conversions.
>
Not exactly. It is true within a domestic environment.
> The question, then, is under what circumstances do such conversions
> occur? The premise of the current proposal is that you don't *do*
> such conversions unless you have provided for polymorphic behavior,
> i.e., virtual functions. Inheritance for factoring and sharing of
> representation and code is fine, but in such applications you
> typically don't rely on derived-to-base conversions.
>
Not entirely true even for a domestic system:
I often have a class hierachy in which the base methods manipulate only on the
part of the base data and no virtualization is required. All the specific
operations in the derived classes will be performed from the specific
interfaces. But I still need a general interface that manipultes all of the
object at the base level. Virtual functions can help a lot in reducing the
neccessity of downcast and hence the need of RTTI. But virtual function does
not always help. Sometimes the specific interfaces and requirements can vary
greatly in derived classes, it is impossible to exract a common interface as a
virtual interface. In this case, I have to use RTTI rather than the virtual
function.
> The challenge, then, for those who view RTTI-via-vtable as
> insufficient is to provide *concrete* counterexamples to this
> assumption: applications where derived-to-base casting does occur
> without the need for virtual functions and for which RTTI would
> nevertheless be useful. Are there such applications?
>
Yes.
I can maintain a group of passive objects without intrinsic behavioral
characteristics, needless to say any virtual functions. What I am concerned is
only the internal data structure. These objects are usually used to carry the
information and to be transfered between different environments. I need RTTI to
represent or transform these objects correctly. For example, to transform an
integer in an object from Intel 8086 form to network form. Although a simple
type id is usually insufficient for this case, but it provides a key to access
the detail type information in some type library generated by the compiler (I
just hate to see the game of waste: inventing one precompiler after another).
My multitasking system can also have an interface that take an object as input
from other task. Such object is not necessarily virtualized. Such type check is
usaually performed at run time. Without RTTI, my task may corrupt due to a
wrong input type. Without language supported RTTI, I have to provide my own
RTTI to solve this problem. If the system is general purposed and must be
integrated with the language environment, again, I have to write a precompiler
to create my own language (example: IDL for remote procedure call)!
And I'm sure many OO database and OS people can tell more.
Since OO technique is aimed mainly to developing large, complex and
coorperative systems, C++, as general purposed OO language, should at least
cover some main application areas.
David Shang
Author: jrobie@netmbx.netmbx.de (Jonathan Robie)
Date: Thu, 30 Jul 1992 07:47:54 GMT Raw View
shang@corp.mot.com (David (Lujun) Shang) writes:
>In article <BryFLI.Hz2@world.std.com> wmm@world.std.com (William M Miller)
>writes:
>function.
>> The challenge, then, for those who view RTTI-via-vtable as
>> insufficient is to provide *concrete* counterexamples to this
>> assumption: applications where derived-to-base casting does occur
>> without the need for virtual functions and for which RTTI would
>> nevertheless be useful. Are there such applications?
>>
The assumption here is that RTTI should be provided only as a means
of safe downcasting within domestic systems. That is obviously nice,
but does nothing to help implement a variety of general purpose tools
which need more information.
>
>And I'm sure many OO database and OS people can tell more.
Well, the biggest problem for OO databases is that the current RTTI
proposal does not give us enough info even for classes *with* virtual
tables.
A less serious problem: it seems silly to force our users to add
virtual methods in order to store a class in the database.
So far I don't think the current RTTI proposal will affect us at all.
We will continue to use our precompiler. I would like to see a better
proposal which would allow us to throw our precompiler away.
>Since OO technique is aimed mainly to developing large, complex and
>cooperative systems, C++, as general purposed OO language, should at least
>cover some main application areas.
Absolutely! The general purpose tools which fit so well into the C++
programming environment are precisely those which need RTTI.
Jonathan
===========================================================================
Jonathan Robie jrobie@netmbx.UUCP
Arnold-Zweig-Str. 44 jrobie@netmbx.in-berlin.de
O-1100 Berlin
Deutschland Phone: +37 (2) 472 04 19 (Home, East Berlin)
+49 (30) 342 30 66 (Work, West Berlin)
--
Jonathan
===========================================================================
Author: shang@corp.mot.com (David (Lujun) Shang)
Date: Mon, 20 Jul 92 22:05:34 GMT Raw View
In article <TMB.92Jul20182052@arolla.idiap.ch> tmb@arolla.idiap.ch (Thomas M.
Breuel) writes:
> As I understand it (I haven't read the proposal), there will
> apparently be a half-hearted attempt at adding runtime type tags to
> some user-defined classes. From the descriptions of the proposal that
> I have heard, that will not be sufficient to make the C++ language
> safe (in the sense of eliminating most sources of "undefined
> behavior"). In fact, at best, it will encourage a careless programming
> style that relies on runtime type tests rather than inheritance and
> virtual functions.
>
I sencond this. As I already said, run time type checking of classes only with
virtual functions is not a serious solution.
David Shang
Author: jrobie@netmbx.netmbx.de (Jonathan Robie)
Date: 20 Jul 92 10:25:18 GMT Raw View
shang@corp.mot.com (David (Lujun) Shang) writes:
>The language should provide run time type checking as well as array bounds
>checking. You can also have a switch to turn off them if you like to.
>
It may be important for compilers to provide such a switch since the
memory overhead needed to store type information for all classes can
be significant. Pragmas would be necessary to switch it on and off
since you might need it for some classes but not for others....messy,
isn't it?
Another possiblity would be to provide a keyword to say that a class
needs to have runtime type identification. This is what we do in our
OO database system, POET. A precompiler looks at your class declarations
and generates runtime type identification if you declare a class using
the "persistent" keyword:
persistent class SomeClassThatNeedsRuntimeInfo {
....
};
This kind of language extension might be the best way to provide run
time type identification. Since many different kinds of applications
might want this info, not just OO databases, it might be nice to use
a more generic word than "persistent."
Providing a typeof() with standard definitions for the standard types
would then be possible. The compiler would know whether this info is
available and could issue appropriate errors at compile time.
Jonathan
===========================================================================
Jonathan Robie jrobie@netmbx.UUCP
Arnold-Zweig-Str. 44 jrobie@netmbx.in-berlin.de
O-1100 Berlin
Deutschland Phone: +37 (2) 472 04 19 (Home, East Berlin)
+49 (30) 342 30 66 (Work, West Berlin)
--
Jonathan
===========================================================================
Author: tmb@arolla.idiap.ch (Thomas M. Breuel)
Date: 20 Jul 92 22:20:52 GMT Raw View
In article <EY048MK@netmbx.netmbx.de> jrobie@netmbx.netmbx.de (Jonathan Robie) writes:
shang@corp.mot.com (David (Lujun) Shang) writes:
>The language should provide run time type checking as well as array bounds
>checking. You can also have a switch to turn off them if you like to.
It may be important for compilers to provide such a switch since the
memory overhead needed to store type information for all classes can
be significant. Pragmas would be necessary to switch it on and off
since you might need it for some classes but not for others....messy,
isn't it?
These are separate issues. A good C++ development system should
compile code that performs array bounds checking and runtime type
checking (I believe only Saber and Purify are "good" in this respect).
Compilers can do this while conforming with the language, and
programmers need do nothing special to take advantage of the facility.
Giving the programmer access to that information in addition to
letting the compiler/runtime system check it, however, constitutes a
language change, since all compilers are then obliged to have these
facilities. Personally, I favor such an approach, but I have little
hope that C++ will change in that direction.
As I understand it (I haven't read the proposal), there will
apparently be a half-hearted attempt at adding runtime type tags to
some user-defined classes. From the descriptions of the proposal that
I have heard, that will not be sufficient to make the C++ language
safe (in the sense of eliminating most sources of "undefined
behavior"). In fact, at best, it will encourage a careless programming
style that relies on runtime type tests rather than inheritance and
virtual functions.
Thomas.
Author: shang@corp.mot.com (David (Lujun) Shang)
Date: Mon, 20 Jul 92 14:57:04 GMT Raw View
> shang@corp.mot.com (David (Lujun) Shang) writes:
>
> >The language should provide run time type checking as well as array bounds
> >checking. You can also have a switch to turn off them if you like to.
> >
>
In article <EY048MK@netmbx.netmbx.de> jrobie@netmbx.netmbx.de (Jonathan Robie)
replies:
> It may be important for compilers to provide such a switch since the
> memory overhead needed to store type information for all classes can
> be significant. Pragmas would be necessary to switch it on and off
> since you might need it for some classes but not for others....messy,
> isn't it?
>
Yes, programs would be a quite mess if the run time type check switch could be
turned on and off from now and then. The swicth is a global switch, you can
only set it either on or off for a single project. In fact, the minimum
requirement for run time type check is quite invisible at the memory overhead
for large systems with a great quantity of memory. Only an additional interger
is required to serve as an internal identifier for each type. However, such
overhead may not be acceptible for systems running on small targets with
limited memory space (sometimes only a few K's). You could turn off the run
time type check switch for developing these systems if you could not stand the
overhead.
However, a internal type identifier alone is sometimes not sufficient to
support a project that requires detailed information about a type. The database
project, as you mentioned, is a good example. It is not practicable to keep
detailed run time type information for each type in the memory (since the big
overhead). Therefore, a keyword for the type which needs detailed type info may
be necessary, just as you suggested:
> Another possiblity would be to provide a keyword to say that a class
> needs to have runtime type identification. This is what we do in our
> OO database system, POET. A precompiler looks at your class declarations
> and generates runtime type identification if you declare a class using
> the "persistent" keyword:
>
> persistent class SomeClassThatNeedsRuntimeInfo {
> ....
> };
>
>
> This kind of language extension might be the best way to provide run
> time type identification. Since many different kinds of applications
> might want this info, not just OO databases, it might be nice to use
> a more generic word than "persistent."
>
In general, a compiler should not throw away the type information when the
compiling finished, at least it should keep the type information for the part
which is used as a specification (since C/C++ is not modularilzed, it is not
easy to incorperate this technique into C/C++). With internal type identifier,
the detailed information for a type should be accessible at run time when it is
required.
David Shang
Author: maxtal@extro.ucc.su.OZ.AU (John MAX Skaller)
Date: Mon, 20 Jul 1992 15:57:53 GMT Raw View
In article <EY048MK@netmbx.netmbx.de> jrobie@netmbx.netmbx.de (Jonathan Robie) writes:
>shang@corp.mot.com (David (Lujun) Shang) writes:
>
>>The language should provide run time type checking as well as array bounds
>>checking. You can also have a switch to turn off them if you like to.
>>
>
>It may be important for compilers to provide such a switch since the
>memory overhead needed to store type information for all classes can
>be significant.
I dont see this unless you have thousands of classes,
and only a few instances of them each.
Anyone any idea of the space overhead of run-time
type info? {Of course, I know, it depends ...}
>Pragmas would be necessary to switch it on and off
>since you might need it for some classes but not for others....messy,
>isn't it?
Or it could be excluded if not needed at link time.
>
>Another possiblity would be to provide a keyword to say that a class
>needs to have runtime type identification.
IMHO run-tim type info is something you should inherit.
If one of your bases has it, you ought to too. If the base doesnt
have it, you cant down cast. That PUBLISHES the availability
of the downcast, I think I would accept this.
>This is what we do in our
>OO database system, POET. A precompiler looks at your class declarations
>and generates runtime type identification if you declare a class using
>the "persistent" keyword:
>
> persistent class SomeClassThatNeedsRuntimeInfo {
> ....
> };
>
>
>This kind of language extension might be the best way to provide run
>time type identification.
Not sure. I am thinking along the lines of something
with access control.
--
;----------------------------------------------------------------------
JOHN (MAX) SKALLER, maxtal@extro.ucc.su.oz.au
Maxtal Pty Ltd, 6 MacKay St ASHFIELD, NSW 2131, AUSTRALIA
;--------------- SCIENTIFIC AND ENGINEERING SOFTWARE ------------------
Author: jbuck@forney.berkeley.edu (Joe Buck)
Date: 21 Jul 92 02:34:06 GMT Raw View
In article <1992Jul20.220534.1365@cadsun.corp.mot.com> shang@corp.mot.com writes:
>As I already said, run time type checking of classes only with
>virtual functions is not a serious solution.
You said it, but you did not justify it. It is completely proper to
design a solution that works only with classes with virtual functions, for
several reasons:
* the virtual impossibility of designing a more general solution that does
not break compatibility with C structs (a requirement that may be
meaningless to theoretical folks but that is nevertheless vital).
This constraint forbids adding any data to the object of any kind.
* the fact that it is trivial to force any class for which run-time type
identification is needed to have a virtual function table (simply add
a virtual destructor).
In most implementations of classes with virtual functions, each object
already has, in effect, a type-ID: the pointer to the virtual function
table. This is a natural hook on which to hang run time type checking.
I could also argue the other way: for a debugger, it isn't enough to
identify all class objects. I also need to be able to identify the
types of any int, double, pointer, or reference variables. There's no
inherent reason why being able to identify all classes, but no other
variable types, is a more natural or useful division that just being
able to identify objects that have virtual functions.
--
Joe Buck jbuck@ohm.berkeley.edu
Author: jrobie@netmbx.netmbx.de (Jonathan Robie)
Date: Tue, 21 Jul 1992 10:30:44 GMT Raw View
maxtal@extro.ucc.su.OZ.AU (John MAX Skaller) writes:
> Anyone any idea of the space overhead of run-time
>type info? {Of course, I know, it depends ...}
>>Pragmas would be necessary to switch it on and off
Think about what you have to store for each class: a complete
set of the data types, including user defined data types.
I suspect that the total minimum memory overhead is similar to having
an extra object or so from each class. If you want to keep strings
around to identify the types (nice for debuggers, class browsers, etc.)
then it gets several times bigger. On a DOS machine this can make
a difference.
> IMHO run-tim type info is something you should inherit.
>If one of your bases has it, you ought to too. If the base doesnt
>have it, you cant down cast. That PUBLISHES the availability
>of the downcast, I think I would accept this.
That certainly has some advantages. Would you rule out a central class
dictionary, then? If not, how would you regulate access to it?
Jonathan
===========================================================================
Jonathan Robie jrobie@netmbx.UUCP
Arnold-Zweig-Str. 44 jrobie@netmbx.in-berlin.de
O-1100 Berlin
Deutschland Phone: +37 (2) 472 04 19 (Home, East Berlin)
+49 (30) 342 30 66 (Work, West Berlin)
--
Jonathan
===========================================================================