Topic: proposal: "virtual restrict" inheritance
Author: dlagno@mail.nnov.ru (Denis Lagno)
Date: Fri, 21 Feb 2003 20:33:19 +0000 (UTC) Raw View
Concerning your example -- earlier in this thread I've posted several
messages. One of them gives clear formal preliminary definition of
restricted inheritance. (w.r.t. == with respect to):
: 10.x Restricted inheritance [class.restrict]
:
: 1 A base class specifier that contains the keyword restrict,
: specifies a restricted direct base class. We say that a class
: without base classes is not restricted w.r.t. any class.
: A class with restricted direct base class R is restricted
: via R w.r.t. R and all base classes of R. A class with direct
: base class B is restricted via B w.r.t. all classes which B
: is restricted w.r.t.
: A class X is restricted w.r.t. to class Y if class X is restricted
: via some class w.r.t class Y.
:
: 2 A program in which some fixed class X is restricted via more
: than one class w.r.t. some fixed class B, is ill-formed.
: [Example:
: class A1 { /* ... /* };
: class A2 { /* ... /* };
: class B1: A1 { /* ... /* };
: class B2: A2 { /* ... /* };
: class C: A1, A2 { /* ... /* };
: class D1: B1, C { /* ... /* };
: class D2: restrict B2, C { /* ... /* };
: class E1: restrict D1 { /* ... /* };
: class E2: D2 { /* ... /* };
: class F: E1, E2 { /* ... /* };
: Here F is restricted via E1 w.r.t. D1, B1, C, A1 and A2.
: F also is restricted via E2 w.r.t. B2 and A2.
: Hence this program is ill-formed. --end example]
So in your example
> B
> / \
> C D
> \ / \
> X Y
> \ /
> W
>
> class B { ... };
> class C: public virtual B { ... };
> class D: public virtual restrict B { ... };
> class X: public C, public D { ... };
> class Y: public D { ... };
> class W: public X, public Y { ... };
>
> Without the "restrict" keyword, we have two instances of D, but
> only one instance of B. What happens with the restrict keyword?
we have:
B is not restricted w.r.t. anything
C is not restricted w.r.t. anything
D is restricted via B w.r.t. B
X is restricted via D w.r.t. B
Y is restricted via D w.r.t. B
W is restricted via X w.r.t. B
and W is restricted via Y w.r.t. B
so W is restricted via more than 1 class w.r.t. fixed class. Hence
your example is ill-formed.
---
> How?
> Why is this good?
let's take an example more advanced than simple rhomb.
B
/ | \
C D E
\ / \ /
X Y
this hierarchy appeared in real-world number-crunching
would-be-high-performance library. The intended interface of that
library is providing "concrete" classes with certain functionality. It
is not supposed that library users will inherit from provided classes
too intensely. So in order to optimize one can define classes as:
class B
{
int m, n;
public:
int virtual crunch() = 0;
...
};
class C: public restrict virtual B { ... };
class D: public virtual B { ... };
class E: public restrict virtual B { ... };
class X: public C, public D { ... };
class Y: public D, public E { ... };
Then compiler can lay out these classes as follows:
#define B_FIELDS() \
void *vtable; \
int m, n;
#define C_FIELDS() \
B_FIELDS() \
C_stuff;
#define D_FIELDS() \
void *vtable; \
D_stuff; \
B_FIELDS()
#define E_FIELDS() \
B_FIELDS() \
E_stuff;
#define X_FIELDS() \
C_FIELDS() \
D_FIELDS()
#define Y_FIELDS() \
E_FIELDS() \
D_FIELDS()
in such a way access to B::n from everywhere except D* is guaranteed
to be at a fixed offset in an enveloping class no matter what class
the most derived object really is. Moreover, any (dynamic) cast, put
it, X* <-> B* now can be performed effectively statically since offset
(0 in that case) is known at compile time whatever class the most
derived object really is. The price is that, for example, user now
cannot inherit both X and Y. Restricted inheritance can be used
dually. One use -- provide compiler with a way to optimize
inheritance but pay the price of somewhat restricting further
inheritance. Second use -- in cases when this price is no price at
all but merit -- when we for example want to implement exclusive
inheritance, we can just write:
class spirit_id {};
class angel_t: restrict spirit_id { ... };
class human_t: restrict spirit_id { ... };
And now we provided guarantee that user cannot be angel and human
simultaneously.
> What would the compiler do differently for
> a "virtual restrict" derivation?
it will not allocate entry in vtable (or in object itself) for offset
(or pointer) of base class. All accesses, all casts to base class
will be resolved statically.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: allan_w@my-dejanews.com (Allan W)
Date: Thu, 13 Feb 2003 19:29:40 +0000 (UTC) Raw View
dlagno@mail.nnov.ru (Denis Lagno) wrote
> [Problem description]
> Imagine that you have typical rhomb shaped inheritance framework
>
> B
> / \
> C D
> \ /
> X
>
> If compiler knows that nothing is grafted badly to this structure in
> other translation units, it can implement one of inheritances
> C:virtual B or D:virtual B not as it usually does -- thru pointer and
> indirect access but directly thru statically known offset.
>
> But since compiler sees only one translation unit at a time it cannot
> do such optimization.
What does it mean for a structure to be "grafted badly?" As opposed
to "grafted well?" I assume "grafted" means "added to the class
heirarchy" i.e. a derived class. But what makes this good or bad?
> [Proposed solution]
> add "virtual restrict" inheritance.
> "virtual restrict" inheritance logically shall be the same as usual
> "virtual" but with one restriction -- if for any derived class some
> base class occurs more than 1 time as "virtual restrict" then the
> program is ill-formed.
So one class gets "virtual restrict" and the others just get "virtual."
Is that right?
What would the compiler do differently for a "virtual restrict"
derivation?
> So changes to standard required are very small and local and without
> possible interference with other language features -- because
> semantically "virtual restrict" shall everywhere act as usual
> "virtual". But beforementioned restriction enables compiler to
> optimize virtual inheritance.
How?
> I assumed that keyword "restrict" already included in C99 so it is
> good to reuse it in another sense in another place.
>
> [example]
> former inheritance framework may be now written as:
>
> class B { ... };
>
> class C: public virtual B { ... };
>
> class D: public virtual restrict B { ... };
>
> class X: public C, public D { ... };
>
> I'll be glad to hear comments.
I don't understand what optimization this makes possible. I suppose
you're saying that the compiler could arrange class B and D next to
each other, so that class D doesn't need to use a pointer to find
the members of B. But surely all the other classes still need that
pointer. Also, what happens if something else derives from C and/or
D? What happens if something derives from both X and Y, where Y
also derives from D?
B
/ \
C D
\ / \
X Y
\ /
W
class B { ... };
class C: public virtual B { ... };
class D: public virtual restrict B { ... };
class X: public C, public D { ... };
class Y: public D { ... };
class W: public X, public Y { ... };
Without the "restrict" keyword, we have two instances of D, but
only one instance of B. What happens with the restrict keyword?
Why is this good?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: dlagno@mail.nnov.ru (Denis Lagno)
Date: Thu, 6 Feb 2003 00:52:05 +0000 (UTC) Raw View
In more formal words.
beginning of [class.derived] clause now states:
###
1 A list of base classes can be specified in a class definition
using
the notation:
base-clause:
: base-specifier-list
base-specifier-list:
base-specifier
base-specifier-list , base-specifier
base-specifier:
::opt nested-name-specifieropt class-name
virtual access-specifieropt ::opt
nested-name-specifieropt class-name
access-specifier virtualopt ::opt
nested-name-specifieropt class-name
access-specifier:
private
protected
public
###
It should be changed to:
###
1 A list of base classes can be specified in a class definition
using
the notation:
base-clause:
: base-specifier-list
base-specifier-list:
base-specifier
base-specifier-list , base-specifier
base-specifier:
::opt nested-name-specifieropt class-name
virtual ::opt nested-name-specifieropt class-name
access-specifier ::opt nested-name-specifieropt
class-name
restrict ::opt nested-name-specifieropt class-name
virtual access-specifier restrictopt ::opt
nested-name-specifieropt class-name
virtual restrict access-specifieropt ::opt
nested-name-specifieropt class-name
access-specifier virtual restrictopt ::opt
nested-name-specifieropt class-name
access-specifier restrict virtualopt ::opt
nested-name-specifieropt class-name
restrict access-specifier virtualopt ::opt
nested-name-specifieropt class-name
restrict virtual access-specifieropt ::opt
nested-name-specifieropt class-name
access-specifier:
private
protected
public
###
As well we should add subclause [class.restrict].
(in following text w.r.t. = with respect to)
###
10.x Restricted inheritance
[class.restrict]
1 A base class specifier that contains the keyword restrict, specifies
a restricted base class. We say that a class without base classes
is not
restricted w.r.t. any class. A class with direct restricted base
class R
is restricted via R w.r.t. R and all base classes of R. A class
with direct base
class B is restricted via B w.r.t. all classes which B is restricted
w.r.t.
A class X is restricted w.r.t. to class A if class X is restricted
via some class w.r.t class A.
2 A program in which some fixed class X is restricted via more than
one class
w.r.t. some fixed class B, is ill-formed.
[Example:
class A1 { /* ... /* };
class A2 { /* ... /* };
class B1: A1 { /* ... /* };
class B2: A2 { /* ... /* };
class C: A1, A2 { /* ... /* };
class D1: B1, C { /* ... /* };
class D2: restrict B2, C { /* ... /* };
class E1: restrict D1 { /* ... /* };
class E2: D2 { /* ... /* };
class F: E1, E2 { /* ... /* };
Here F is restricted via E1 w.r.t. D1, B1, C, A1 and A2. F also is
restricted
via E2 w.r.t. B2 and A2. Hence this program is ill-formed. --end
example]
###
OK, what problems does it solve??
(1) it enables optimisation of virtual inheritance that cannot be done
if compiler sees only 1 translation unit.
(2) problem raised by Daniel Gutson -- how implement exclusive
inheritance.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: dlagno@mail.nnov.ru (Denis Lagno)
Date: Sun, 2 Feb 2003 20:23:52 +0000 (UTC) Raw View
[Problem description]
Imagine that you have typical rhomb shaped inheritance framework
B
/ \
C D
\ /
X
If compiler knows that nothing is grafted badly to this structure in
other translation units, it can implement one of inheritances
C:virtual B or D:virtual B not as it usually does -- thru pointer and
indirect access but directly thru statically known offset.
But since compiler sees only one translation unit at a time it cannot
do such optimization.
[Proposed solution]
add "virtual restrict" inheritance.
Now standard says
# For an object of class AA, all virtual occurrences
# of base class B in the class lattice of AA correspond
# to a single B subobject within the object of type AA,
# and every other occurrence of a (non-virtual) base
# class B in the class lattice of AA corresponds
# one-to-one with a distinct B subobject within
# the object of type AA.
"virtual restrict" inheritance logically shall be the same as usual
"virtual" but with one restriction -- if for any derived class some
base class occurs more than 1 time as "virtual restrict" then the
program is ill-formed.
So changes to standard required are very small and local and without
possible interference with other language features -- because
semantically "virtual restrict" shall everywhere act as usual
"virtual". But beforementioned restriction enables compiler to
optimize virtual inheritance.
I assumed that keyword "restrict" already included in C99 so it is
good to reuse it in another sense in another place.
[example]
former inheritance framework may be now written as:
class B { ... };
class C: public virtual B { ... };
class D: public virtual restrict B { ... };
class X: public C, public D { ... };
I'll be glad to hear comments.
--
Denis
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: dlagno@mail.nnov.ru (Denis Lagno)
Date: Mon, 3 Feb 2003 19:57:39 +0000 (UTC) Raw View
Oh! BTW. Look at parallel thread with Daniel's proposal about
exclusive inheritance. It seems to me that my proposal as well solves
that problem just as a byproduct.
You just do something like
class solitair_t {};
class Human: public virtual restrict autism_t { ... };
class Engel: public virtual restrict autism_t { ... };
and then you cannot inherit from both..
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: dlagno@mail.nnov.ru (Denis Lagno)
Date: Mon, 3 Feb 2003 19:59:38 +0000 (UTC) Raw View
> [Proposed solution]
> add "virtual restrict" inheritance.
In principle it would be enough, but for the sake of clarity and
homogenty I think we should allow also nonvirtual restrict
inheritance. So "restrict" will be just another modifier of
inheritance, similar to virtual.
Semantics shall be as follows: if some base class occurs in some
derived class more than 1 time as "restrict" base class then the
program is ill-formed. Diagnostic seems to be straightforward.
--
Denis
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]