ORBit mail 1 - Multiple-inheritence



Dealing with Multiple Inheritence in ORBIT (for in-process binary
objects)
-----------------------------------------------------------------

<N.B.> 
In this text file I use the acronyms epv and vepv. These are from
the corba spec C language mapping (section 19.26.4) and correspond to
'entry point vector' and 'virtual entry point vector'. Loosely, an epv
is a table of pointers to functions (like a vtable in C++ speak), and
an vepv is a table of epvs (i.e. an table of tables of pointers to
functions).


The Problem
-----------

The current ORBit VTable scheme (as I understand it) can't handle
implicit upcasting within MI of interfaces.


interface intf1
{
    op1();
    op2();
}

interface intf2 
{
    op3();
    op4();
    op5();
}

interface intf3 : intf1 intf2
{
    op6();
}


For an object supporting intf3 as its most derived interface, the
current method table layout looks like this:


Object      VEPV            EPVs
------     ------         ---------

vepv ---> intf1_epv -------> op1
 ...      intf2_epv ----.    op2
<data>    intf3_epv --. |
 ...                  | `--> op3
                      |      op4
                      |      op5
                      |
                      `----> op6


And the client has a set of functions (or in the proposed ORBit
C-mapping, macros for efficiency) for objects of type intf3 which do
the lookup and invoking of the methods implicitly:

e.g. 

#define intf3_op1(_handle, evptr) \
((CORBA_Object)_handle->vepv[0])->op1(_handle, evptr)

... ...

#define intf3_op6(_handle, evptr) \
((CORBA_Object)_handle->vepv[3])->op6(_handle, evptr)



The problems come when you attempt to implicitly upcast an object
pointer. Implicit upcasting is when you treat a pointer to a derived
class as if it were a pointer to a base class without any change to
that pointer.

The corba C-mapping (section 19.4) says that a programmer
should be able to invoke functions from the base interfaces using
objects of derived types. 

e.g.

      intf3_op2(intf3_instance,&env);         

results in the same operation as

      intf1_op2(intf3_instance,&env);


Which works fine in our example for upcasts to intf1 (since intf1_epv is
at the top of the vepv), however it won't work for intf2. This is
because under the current strategy, the function expecting an object
supporting intf2 as its most derived interface expects the vtable
layout to look like this:


Object      VEPV           EPV
------     ------        ---------

vepv ---> intf2_epv -----> op3
                           op4
                           op5
                       

and so will map intf2_op3 like this:

#define intf2_op3(_handle, evptr) \
((CORBA_Object)_handle->vepv[0])->op3(_handle, evptr)

which will fail on the intf3 object vepv layout.


So how do other Corba C-mappings handle binary MI?
--------------------------------------------------

They don't. Other Corba implementations don't handle in-process
objects, and so the invocation information is incoded 'on the wire'
and then unpacked and dynamically translated by the server. This
allows all the client stub functions refering to the same
operation on seperate interfaces to contain the same code.

What about other binary object architectures?
---------------------------------------------

COM - Microsoft's Component architecture handles binary MI upcasting
through a dynamic casting function called QueryInterface, which is in
the root interface that every COM interface inherits from. It also
uses a slightly different object model to increase efficiency and
allow for easy object versioning. 


C++ also provides binary Multiple Inheritence. In C++, casting up a
multiple inheritence tree is done using some 'behind the scenes'
compiler magic.

In C++, if you do:

    intf3* f3 = <...create an intf3 implementation...>
    intf2* f2 = f3;

you'll find that f2 does not point to the same address as f3 - the
compiler has offset the object pointer so that it points to an intf2
vtable. (It's actually more complicated than this because it has to
handle the data members and possible virtual inheritence as well, but
the principle is the same).



Suggestions for ORBit
---------------------

Either we ditch Multiple Inheritence, or we ditch the implicit casting
part of the C-language mapping - AFAIK we can't have both without gross
inefficiency.

I don't think we should ditch multiple inheritence because it is a
cornerstone of the corba object model. In addition, it is very useful
for mix-in objects. These are objects which support interfaces that
are not part of their 'semantic' type but merely add some extra
functionality - e.g. To make objects 'streamable' by adding the
streamable interface to the inheritence tree.

Ditching the implicit upcasting rule from the C-Mapping means
providing an explicit way of casting object pointers to their base
interfaces. This may be a function or macro.


-- 
_______________________________________________________________________
 Phil Dawes                               |   My opinions are my own
 WWW:    err.. temporarily non-existant   |   and nothing to do with
 Email:  philipd@parallax.co.uk           |      my employer.



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]