Topic: Objects already contain type information => binary virtual functions
Author: ngo@tammy.harvard.edu (Tom Ngo)
Date: 28 Mar 91 14:36:48 GMT Raw View
Here's a wild idea whose purpose is to permit typesafe downcasts under
certain circumstances. Do others think it's worth pursuing? Can it
be generalized?
The problem:
class B {
virtual void foo(B*);
};
class D : public B {
virtual void foo(D*);
};
void bar(B* b1, B* b2) {
b1.foo(b2);
}
D d1;
D d2;
bar(&d1,&d2); // I want D::foo to be invoked
Currently, D::foo does not override B::foo. A way to cause this
to happen is for D::foo to be declared D::foo(B*) and downcast B*
to D* within the body of D::foo. This downcast is considered
unsafe; see ARM p. 210-211.
I call foo() a "binary" virtual function, meaning that the
intention is for it to operate on two objects of identical type,
even if the call is made with references or pointers to a base
class of the type.
I feel there is a strong need for such functions, and that
currently there is no way to implement them that is both typesafe
and elegant. For example, if you have a container class designed
to take B*'s and you have given it all D*'s, the container class
ought to be able to do things like compare objects in a D-specific
manner, etc. Right now if you want to implement this sort of
thing in a typesafe manner you have to make two separate virtual
function calls, one for each operand of the comparison, or some
such thing.
The proposed solution:
It has been argued that to implement typesafe downcasts would
require that type information be added to each object. I suggest
that objects already contain type information in their virtual
function tables. So here's the idea:
1. Relax the requirement that two functions' arguments match
EXACTLY for one to override the other. Instead, permit
D::foo(D*) to match B::foo(B*).
(In general, any argument of type D* or D* in the argument
list of D::foo would match an argument of type B* or B* in
B::foo.)
2. In that case, in D::foo(D* that) the compiler should
automatically generate code that ensures:
this->foo == that->foo
(You know what I mean.) If the equality fails, then perhaps
an addressing exception should be generated.
This solution generalizes trivially to cases in which D::foo has
several D* arguments.
Comments?
--Tom
--
Tom Ngo
ngo@harvard.harvard.edu
617/495-1768 lab number, leave message
Author: chip@tct.com (Chip Salzenberg)
Date: 31 Mar 91 19:47:51 GMT Raw View
According to ngo@tammy.harvard.edu (Tom Ngo):
>The problem:
>
> class B {
> virtual void foo(B*);
> };
> class D : public B {
> virtual void foo(D*);
> };
>
> void bar(B* b1, B* b2) {
> b1.foo(b2);
> }
>
> D d1;
> D d2;
> bar(&d1,&d2); // I want D::foo to be invoked
To suppose that D::foo() should override B::foo() is to misunderstand
the meaning of virtual functions, namely:
A virtual function is _one_ function with potentially many
implementations.
The code quoted above shows that D::foo() is prepared to work on a D,
while B::foo() is prepared only for a B. Thus they are not the same
function. They may be equivalent in one way or another; they may even
have the same body. But they are not the _same_ function. So the use
of "virtual" for these two functions is a design error.
--
Chip Salzenberg at Teltronics/TCT <chip@tct.com>, <uunet!pdn!tct!chip>
"All this is conjecture of course, since I *only* post in the nude.
Nothing comes between me and my t.b. Nothing." -- Bill Coderre