Yet More on MI

Hans-Dieter.Dreier@materna.de Hans-Dieter.Dreier@materna.de
Wed, 17 Mar 1999 18:04:47 +0100


--niWO8o7uApPVPHJTV8IQB7FnAL8o8Vmq
Content-type: text/plain; charset="ISO-8859-1"
Content-transfer-encoding: quoted-printable

Yet More on MI
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D

After contemplating the MI problem a little more a came upon the approach I=
 want to sketch below.
Please have a look at it and tell me about any flaws you can find in it.

First, the goals I want to achieve:

1. Provide true MI functionality to the user (How it works internally is an=
other issue).

2. No bidirectional class dependency: Make sure no base class needs recompi=
lation when a derived class changes.
I'm not addressing the issue of "virtual/static" here, assuming that either=
 the user specifies what he wants or everything is virtual.

3. Be reasonably efficient.


Internally, this approach would use cMI since IMO the above conditions rule=
 out instance merging.
So one of the base classes will be "more equal" than the others.
I'll call that class the "MI class". The others will be called "mixed-n" cl=
asses here to distinguish them.


The proposed instance layout would be:


this -> - Reference to MI class if used as mixed-class, pointer to this oth=
erwise (Note a)
        - Reference to vtable (Note b)
        - Reference to ttable (Note c)
        - (Instance items if any)

Note a:
If a reference to this is used in the program itself, a reference to the MI=
 object is wanted rather than a reference to the mixin object.
That's what this instance item is good for.

Note b:
This will be the vtable as commonly used.
Each virtual item that has been declared here or in one of the base classes=
 has a slot assigned by the compiler in which its address is stored.
Vtable layout of base classes is preserved; entries for virtual items in th=
e current class are appended.
The vtable may be shared among all instances of that class that are used in=
 the same mixin declaration (or as a standalone class).
This is because the compiler may need to change entries' values if the MI c=
lass (or one of the other mixins) overrides virtual items of this (mixin) c=
lass.
Example: Let there be instances of class A as a standalone class as well as=
 (implicit) instances that are used as mixins.
Then there will be two versions of the vtable, one for each usage.

Note c:
For each vtable entry this table will contain the this pointer that needs t=
o be used with that entry
(ie he reference to the instance that actually contains the item).
If the item is taken from the MI class, it will be a pointer to the MI clas=
s's instance;
if it was taken from a mixin (of the MI class) it will be one to that mixin=
's instance.
Because it contains this's, I'll call it the "ttable".
The value will be used as a this pointer for actual item access (for virtua=
l calls; simple data accesses may not need it).
This makes sure that a method will always be called with the proper this va=
lue (ie consistent with instance layout)
which for mixins is different from the MI object's this value.
Since the ttable contains references to instances, each instance needs its =
own table.
Therefore the ttable may be contained inside the instance rather than being=
 referenced by a pointer.
If it is kept as a separate entity (I won't call it an object), the referen=
ce may be NULL if the instance was not used as a mixin,
thus saving space (and one indirection) at the expense of having to check f=
or a NULL on every virtual call.
If it is NULL, "this" will be used.


Here's an example.

class A {int a; virtual va1; virtual va2;}	// not "pure virtual" but overri=
deable is meant
class B {int b; virtual vb1; virtual vb2;
    virtual va1 =3D 0;}                           // va1 is pure virtual (i=
e used here, defined elsewhere)
class C {int c; mixin A ca; mixin B cb;         // contains 2 mixins
    int va2; int vb2;                           // va2 and vb2 are overridd=
en
    virtual va1 =3D 0;}                           // va1 is pure virtual (i=
e used here, defined elsewhere)

A AnA;      // A used standalone
C aC;       // A used as a mixin (together with B)


The memory layout looks like this:

AnA: =

    AnA            // MI class instance: If you check "this =3D=3D aC" insi=
de A standalone you get false because this is AnA
    vtable of A standalone
    ttable of AnA  // might be NULL, see Note c
    a

vtable of A standalone:
    va1 of A
    va2 of A

ttable of AnA:     // might be missing, see Note c
    AnA
    AnA

(This was easy.)


aC:
    aC              // MI class instance
    vtable of C
    ttable of aC
    c
    ca
    cb

vtable of C:
    va1 of A

ttable of aC:
    ca             // va1 always operates on an A if taken from A

ca:
    aC             // MI class: If you check "this =3D=3D aC" inside mixin =
A ca you get true
    vtable of mixin A ca
    ttable of ca
    a

vtable of mixin A ca:
    va1 of A
    va2 of C       // overridden by C

ttable of ca:
    ca
    aC

cb:
    aC
    vtable of mixin B cb
    ttable of cb
    b

vtable of mixin B cb:
    vb1 of B
    vb2 of C       // overridden by C
    va1 of A       // found in A

ttable of cb:
    cb
    aC
    ca
    =


--

Regards,

Hans-Dieter Dreier
(Hans-Dieter.Dreier@materna.de)=

--niWO8o7uApPVPHJTV8IQB7FnAL8o8Vmq
Content-type: text/plain; charset="ISO-8859-1"
Content-transfer-encoding: quoted-printable

IDENTIFIKATIONSANGABEN:
a22317a.txt IA5 DX-MAIL X.400 User Agent=

--niWO8o7uApPVPHJTV8IQB7FnAL8o8Vmq--