[comp.object] Shippable C++ Objects

davidm@uunet.UU.NET (David S. Masterson) (11/16/89)

			Request for Comments
			  (*please post*)

Based on previous discussions within these groups and some work I am currently
doing, I'd like to get some comments (please post) on the following ideas for
the shipment of C++ objects between processes (and, by implication, the
persistence of the object).  Hopefully, this will generate some interesting
discussions.  Below I list some ideas/requirements for the shippability
between processes of general objects in C++:

1.  Assume an Event interface between processes.  Therefore, when shipping an
object, you can be very sure that something on the other side (in this case,
a callback) will understand what it is because of the event type.

2.  Assume each class of objects has methods for building a shippable byte
array representation of the object and returning a pointer to that shippable
form.  This means that each object is responsible for building a shippable
form of itself.  By implication, the parent of the object and contained
objects can build shippable representations of themselves and, so, are called
at appropriate times by the child's shippable method, which then copies the
information into its shippable form.  This capability MUST exist on an object
for an object to be shipped (the implications for storage are similar if not
the same).

3.  Assume each class of objects has methods for filling (or constructing)
itself from the shippable byte array representation made in (2).  Since the
object knows what it did to create (2), it should know what it can do to get
itself back from that (2) (most likely a reverse operation).  Therefore, all
initilization functions would only need to take a char* (void* ??) pointer.
This also implies that Event objects need only contain some header followed by
an object type and an unknown length byte array.

4.  All parts of an object must be handled in (2) and (3), even to the point
of just deciding that part of an object doesn't need to be shipped.
Therefore, even memory pointers must be resolved in the processing of (2) and
(3).

5.  Base type objects are copiable into shippable objects as is.  Their size
and type will be well-known by both sides of the shipping software, so the
only thing to resolve is recognizing them in the stream of bytes.  If all
other aspects of shippability are resolved, then recognition is not necessary
as they MUST be at well-known spots in the data stream.

6.  Copying of object contents out of shippable form MUST be done with
knowledge of copying the object contents into shippable form.  Suggested might
be that an object gets its parent shippable form, followed by top to bottom
contents of itself (NOTE: next paragraph) and copies those into the shippable
output form for the current object.  The initializer from a shippable form
would then unwind this in a similar manner.

7.  Memory pointers are the special case.  In the process of encountering a
memory pointer, converting to shippable form seems to require a need for a
symbol table.  Basically, the value of the memory pointer would be given to
the symbol table which would return a symbol for that memory pointer (either a
new one or the previous one).  If the symbol table says that this memory
pointer has been seen before, then there is nothing to do other than copy the
symbol (with the Seen_Before flag) into the byte stream.  If the memory
pointer is new to the symbol table, then the symbol is copied to the byte
stream (with the New flag) and the pointer is then followed to produce the
shippable form of what it points to.

8.  This may lead to one extra copy of an object in the shippable stream due
to the potential for a circular pointer chain.  This should be resolvable by
well-known methods and object design criteria.  For instance, it is highly
unlikely (read NEVER HAPPEN) that one object would point into the middle of
another object (especially with the tendancy toward private data), so putting
the memory address of each new object as a whole in the symbol table and a
corresponding symbol into the byte stream should eliminate the possibility of
circular reference problems in object pointer chains.  That is, when
processing an object, enter its memory address into the symbol table so that
if any succeeding objects point to it, no further processing need be done.  In
the case of circular pointers from ivar to ivar within an object, they should
be resolvable through the definition of the object (the designer should be
able to handle it).

9.  Reconstructing the object on the other side would mean nothing more than
copying well-known values from the byte stream into their proper places and
doing some special tracking of pointer symbols in the byte stream to make sure
they get relinked properly.  When a pointer type is encountered in
constructing an object, a symbol had better be on the input stream (trust the
transmission media).  This symbol would be stripped out and the symbol table
queried to determine if it has been seen before.  If not, an object is
new()'ed and a char* pointer to the area after the symbol in the byte stream
would be passed to its init function (after the value of new() is entered in
the symbol table).  If it has, then the value is copied from the symbol table
into the current pointer.

10.  If the methods for build_shippable() and init_from_shippable() are
virtual on the object, then object type for the shippable form will have to be
correct even if the object referred to when build_shippable() is invoked is of
pointer to parent type.  Because the object type will be correct, then the
proper event callback on the other side will get invoked.

11.  The implication of all this is that objects that are virtual in nature
and have memory pointers imbedded in them can be shipped from process to
process without much work and, therefore, object instances may be passed back
and forth without limitation on their representation in the C++ sense.

For example:

	class A {			class X {
		X *alpha;			int abc, cde;
	}				}
	class B:A {			class Y {
		Y *beta;			float m, n;
	}				}
	class C:B {			class Z {
		Z *gamma;			char x[10];
	}				}

would translate into:

	Shippable_of_C {		Symbol		Value
		Label(C);		Label(C)	&C
		Label(C);		Label(C)	&B
		Label(C);		Label(C)	&A
		Label(X);		Label(X)	&X
		Label(X);		Label(Y)	&Y
		int	abc, cde;	Label(Z)	&Z
		Label(Y);
		Label(Y);
		float	m, n;
		Label(Z);
		Label(Z);
		char	x[10];
	}

Decomposition of this should be relatively easy.  The internal format
of Shippable_of_C is not important, so long as (2) and (6) are
followed carefully.

Note that when C enters the address of itself into the Symbol Table,
the returned value will also suffice for both B and A.  The two extra
Label(C) values in the Shippable form are necessary, though, as the
init_from_shippable() function for each object cannot make assumptions
about whether it has children or not.  Therefore, initializing C will
strip the first Label(C) and call initialize of B (which will strip
the second and so on...).

Also note that when (say) B is processing the pointer to Y, it knows
it is processing a pointer and, therefore, should expect Label(Y) on
the input stream.  It can then strip this value and enter it with the
address of the Y object that it will next allocate (with new()).  It
should not call a constructor for Y with the values in the stream
until it has entered the address of Y into the symbol table.  This is
in case of circular references within Y.  So it calls "new Y()",
enters the returned value into the symbol table, then calls "Y.init()"
with the char* (void* ??) pointer to the area after the Label(Y) to
get it initialized.  Y will then strip the expected Label(Y) and enter the
following information in the byte stream into itself.


--
===================================================================
David Masterson					Consilium, Inc.
uunet!cimshop!davidm				Mt. View, CA  94043
===================================================================
"If someone thinks they know what I said, then I didn't say it!"

richard@pantor.UUCP (Richard Sargent) (11/16/89)

[edited quote follows]

> From: cimshop!davidm@uunet.UU.NET (David S. Masterson)
> Newsgroups: comp.lang.c++,comp.object
> Subject: Shippable C++ Objects (RFC)
> Message-ID: <CIMSHOP!DAVIDM.89Nov15101037@uunet.UU.NET>
> Date: 15 Nov 89 18:10:37 GMT
> 
> 			Request for Comments
> 			  (*please post*)
> 
> Based on previous discussions within these groups and some work I am currently
> doing, I'd like to get some comments (please post) on the following ideas for
> the shipment of C++ objects between processes (and, by implication, the
> persistence of the object).  Hopefully, this will generate some interesting
> discussions.  Below I list some ideas/requirements for the shippability
> between processes of general objects in C++:
> 

...

> 
> 3.  Assume each class of objects has methods for filling (or constructing)
> itself from the shippable byte array representation made in (2). ...

Here's the nub of the problem! The rest of the proprosal is quite
straight forward. In fact, I believe that I read a paper on this
in one of the OOPSLA or C++ Workshop proceedings.

"The object can reconstruct itself from the byte stream" requires
that the object already exist. It still seems to me that you *have*
to have a case statement somewhere which knows about all (interesting)
object classes. The cases create each new type of object, probably using
a class constructor which has a ByteStreamRepresentation argument.
The created object is then added into the receiving program's
organization. How to do this from a general purpose class library
without encoding knowledge of the application is another (lesser)
problem.

The real trick will be to eliminate the need for such a switch!
If anyone figures this out for C++, I'm waiting with bated breath
for the answer.

...

> --
> ===================================================================
> David Masterson					Consilium, Inc.
> uunet!cimshop!davidm				Mt. View, CA  94043
> ===================================================================
> "If someone thinks they know what I said, then I didn't say it!"

I sure would like to see a viable general purpose solution to this
problem in C++. I'm afraid that the solution will require a lot
of the facilities from Smalltalk.


Richard Sargent                   Internet: richard@pantor.UUCP
Systems Analyst                   UUCP:     uunet!pantor!richard

peterd@cs.washington.edu (Peter C. Damron) (11/17/89)

In article <CIMSHOP!DAVIDM.89Nov15101037@uunet.UU.NET> cimshop!davidm@uunet.UU.NET (David S. Masterson) writes:
>... I'd like to get some comments (please post) on the following ideas for
>the shipment of C++ objects between processes (and, by implication, the
>persistence of the object).

>1.  Assume an Event interface between processes.  Therefore, when shipping an
>object, you can be very sure that something on the other side (in this case,
>a callback) will understand what it is because of the event type.

How does the event type relate to the object type/class?
How do you assure that the object methods are the same in both processes?
I assume that the different processes are in different address spaces.

>2.  Assume each class of objects has methods for building a shippable byte
>array representation of the object ...

>3.  Assume each class of objects has methods for filling (or constructing)
>itself from the shippable byte array representation made in (2)...

It sounds to me like you are implementing write() and read() in 2 & 3.

>4.  All parts of an object must be handled in (2) and (3), even to the point
>of just deciding that part of an object doesn't need to be shipped.
>Therefore, even memory pointers must be resolved in the processing of (2) and
>(3).

If you want to ship a single node, do you have to ship the whole graph
that contains it?

>7.  Memory pointers are the special case.  In the process of encountering a
>memory pointer, converting to shippable form seems to require a need for a
>symbol table...

Now this is the hard part.  What you want is remote & local references
to objects (everything is an object right?).

>9.  Reconstructing the object on the other side would mean nothing more than
>copying well-known values from the byte stream into their proper places and
>doing some special tracking of pointer symbols in the byte stream to make sure
>they get relinked properly...

It sounds like you are limiting the shippable format to be an LL(0) language.
This may be too restrictive.

>10.  If the methods for build_shippable() and init_from_shippable() are
>virtual on the object, then object type for the shippable form will have to be
>correct even if the object referred to when build_shippable() is invoked is of
>pointer to parent type.  Because the object type will be correct, then the
>proper event callback on the other side will get invoked.

How do you represent virtual pointers accross processes?
I get the feeling you thought about data but not code.

I suggest you read about systems that have already tried to deal with
distributed objects, like Eden and Emerald here at University of Washington.
Try the references below for starters.

Hope this helps,
Peter.

---------------
Peter C. Damron
Dept. of Computer Science, FR-35
University of Washington
Seattle, WA  98195

peterd@cs.washington.edu
{ucbvax,decvax,etc.}!uw-beaver!uw-june!peterd
---------------

%T Distribution and Abstract Types in Emerald
%A Andrew P. Black
%A Norman C. Hutchinson
%A Eric Jul
%A Henry M. Levy
%A L. Carter
%J IEEETSE
%V 13
%N 1
%D JAN 1987

%T Fine-Grained Mobility in the Emerald System
%A Eric Jul
%A Henry M. Levy
%A Norman C. Hutchinson
%A Andrew P. Black
%J TOCS
%D FEB 1988

%T Replication in Distributed Systems: The Eden Experience
%A Jerre D. Noe
%A Andrew Proudfoot
%A Calton Pu
%J PROC Fall Joint Computer CONF (FJCC)
%C Dallas, TX
%D NOV 1986
%P 1197-1208

%T The Architecture of the Eden System
%A Edward D. Lazowska
%A Henry M. Levy
%A Guy T. Almes
%A Michael J. Fischer
%A Robert J. Fowler
%A Stephen C. Vestal
%J PROC 8th SYMP on Operating Systems Principles
%D DEC 1981
%P 148-159

db@helium.East.Sun.COM (David Brownell) (11/17/89)

In article <31.UUL1.3#5109@pantor.UUCP>
	richard@pantor.UUCP (Richard Sargent) writes:
>
>> From: cimshop!davidm@uunet.UU.NET (David S. Masterson)
>> Subject: Shippable C++ Objects (RFC)
>> 
>> 3.  Assume each class of objects has methods for filling (or constructing)
>> itself from the shippable byte array representation made in (2). ...
>
>Here's the nub of the problem! The rest of the proprosal is quite
>straight forward. In fact, I believe that I read a paper on this
>in one of the OOPSLA or C++ Workshop proceedings.

It's also, surprise!, essentially the same idea that shows up in
networking for how to serialize and deserialize RPC arguments.
Commercial implementations of the idea (not in C++) include
XDR, ASN.1, and an analogue that NCS's NIDL compiles into (sorry,
I forget the name).

If you've never looked at RPC systems before, do so -- you'll find
that they look very much like distributed object systems.  (Sun's
RPC has a limitation of one object per type per system, but then
again any OO programmer worth his/her salt can implement objects
that manage access to many other objects ... like NFS does for "file"
objects, for example.)

>"The object can reconstruct itself from the byte stream" requires
>that the object already exist. It still seems to me that you *have*
>to have a case statement somewhere which knows about all (interesting)
>object classes. The cases create each new type of object, probably using
>a class constructor which has a ByteStreamRepresentation argument.

Sort of; "object" is distinct from a data format.  The process is taking
data in one format from one data store into another, and constructing a
NEW object by binding methods to the new data representation.  What's
shipped is data, not data plus code, and the new methods might not
implement the class used by the message sender. The key points are needing
to use a constructor function, and needing to choose which of several
constructors to use.

No application will be able to understand all types/classes ... they get
incrementally added to real systems over time.  Apps need to be able to
reject or ignore message types they can't understand by examining a type
code stored early in the message; there's a "default" branch in that
case statement!

>The created object is then added into the receiving program's
>organization. How to do this from a general purpose class library
>without encoding knowledge of the application is another (lesser)
>problem.

One interesting trick, irrelevant to today's C++, is to ship source
code implementing the class (including its deserializing code) to the
message recipient when it needs it.  This is what NeWS does, and
probably some other systems I don't know about.  (I can't see any
reasonable networked implementation of Lisp not supporting this,
for example!)  This still doesn't get away from needing to know the
type of the message ("source code followed by data").

    David Brownell			db@east.sun.com
    Sun Desktop Systems Software	sun!suneast!db
    Billerica, MA

vaughan@mcc.com (Paul Vaughan) (11/17/89)

	"The object can reconstruct itself from the byte stream" requires
	that the object already exist. It still seems to me that you *have*
	to have a case statement somewhere which knows about all (interesting)
	object classes.

Suppose that in the byte stream there is some token that uniquely
identifies the class of the the object being transmitted.  Then that
token could be used to look up in a table a function to be called to
create such an object.  So, you don't have to have a case statement
(other techniques are possible), but you do have to somehow know of
all interesting classes.  A further technique would be to transmit a
pathname through the byte stream and to use that to dynamically load a
class definition.  It would still be important to have a table of the
classes that were already loaded.

 Paul Vaughan, MCC CAD Program | ARPA: vaughan@mcc.com | Phone: [512] 338-3639
 Box 200195, Austin, TX 78720  | UUCP: ...!cs.utexas.edu!milano!cadillac!vaughan

davidm@uunet.UU.NET (David S. Masterson) (11/18/89)

In article <9832@june.cs.washington.edu> peterd@cs.washington.edu (Peter C. Damron) writes:
   In article <CIMSHOP!DAVIDM.89Nov15101037@uunet.UU.NET> cimshop!davidm@uunet.UU.NET (David S. Masterson) writes:
   >1.  Assume an Event interface between processes.

   How does the event type relate to the object type/class?
   How do you assure that the object methods are the same in both processes?

The natural assumption is that if I have a byte stream that represents an
object to be sent to another process, I will issue an event to that process
that will cause that process to invoke the reconstruction method.  My
assumption (perhaps invalid) was that all processes are built from the same
object library, therefore the object methods are the same in both processes
because its the same object class.  There has to be some assumptions that the
project that both processes are involved in are part of the same effort (in
other words, they reuse each others code).

   >2.  Assume each class of objects has methods for building a shippable byte
   >array representation of the object ...
   >3.  Assume each class of objects has methods for filling (or constructing)
   >itself from the shippable byte array representation made in (2)...

   It sounds to me like you are implementing write() and read() in 2 & 3.

Exactly!  Except that this write() and read() are to memory instead of to disk
(this should give a C++ program more flexibility in what to do with that
object).  Now the application, not the object, has the choice of where to send
the object and how to get it there (this might be wrapped in a higher object).

   >4.  All parts of an object must be handled in (2) and (3), even to the
   >  point of just deciding that part of an object doesn't need to be shipped.

   If you want to ship a single node, do you have to ship the whole graph
   that contains it?

Would the node make sense to the receiving process without the object that its
next pointer points to?  If so, then that comes under the heading of "doesn't
need to be shipped" (at least this particular time).  However, if you ship a
node to another process without the object that is referred to by the node's
next pointer (essentially just the data within the node), is it still a node?

   >7.  Memory pointers are the special case.

   Now this is the hard part.  What you want is remote & local references
   to objects (everything is an object right?).

I'm not sure what you mean here.  Each process will use the object in its
non-shipped, internal form, so to each process the object will be local at the
time of its reference.  Its up to the application to decide whether there are
any conflicts (from a lock standpoint) about this way of doing business.

   >9.  Reconstructing the object on the other side would mean nothing more
   >  than copying well-known values from the byte stream into their proper
   >  places and doing some special tracking of pointer symbols in the byte
   >  stream to make sure they get relinked properly...

   It sounds like you are limiting the shippable format to be an LL(0)
   language.  This may be too restrictive.

Why?  The shippable format only exists during the move of an object from one
process to another.  Breaking an object down into simple terms for this
purpose should make it easier to work with.

   >10.  If the methods for build_shippable() and init_from_shippable() are
   >  virtual on the object, then object type for the shippable form will have
   >  to be correct even if the object referred to when build_shippable() is
   >  invoked is of pointer to parent type.  Because the object type will be
   >  correct, then the proper event callback on the other side will get
   >  invoked.

   How do you represent virtual pointers accross processes?
   I get the feeling you thought about data but not code.

Since the processes are dealing with the same class of object, then virtual
pointers should take care of themselves (they must be right for the particular
process).  Code cannot be shipped, therefore the implication is that both
processes are already compiled with the same code.  Since the "linearization"
of the object by the method I have suggested deals with each object in an
object to be shipped individually, virtual pointers can be safely ignored
(they are outside the definition of an object) because each object only deals
with what it knows about.  Therefore, the callback method via the event type
will know what object needs construction and so construct it with the proper
virtual functions already there.

   I suggest you read about systems that have already tried to deal with
   distributed objects...

I'll try, but the company I work for doesn't have ready access to a reference
library.

   Peter C. Damron
   Dept. of Computer Science, FR-35
   University of Washington
   Seattle, WA  98195

   peterd@cs.washington.edu
   {ucbvax,decvax,etc.}!uw-beaver!uw-june!peterd

--
===================================================================
David Masterson					Consilium, Inc.
uunet!cimshop!davidm				Mt. View, CA  94043
===================================================================
"If someone thinks they know what I said, then I didn't say it!"

davidm@uunet.UU.NET (David S. Masterson) (11/18/89)

In article <31.UUL1.3#5109@pantor.UUCP> richard@pantor.UUCP (Richard Sargent) writes:

   [edited quote follows]

   > From: cimshop!davidm@uunet.UU.NET (David S. Masterson)

   ...

   > 
   > 3.  Assume each class of objects has methods for filling (or constructing)
   > itself from the shippable byte array representation made in (2). ...

   Here's the nub of the problem! ...
   The real trick will be to eliminate the need for [...] a switch!
   If anyone figures this out for C++, I'm waiting with bated breath
That was why I suggested the Event interface (a la X windows) as the method
for passing things to new processes.  Each Event would be registered with an
appropriate callback (which might be wrappable as an object).  Therefore,
whenever an application takes on new functionality, it acquires a new callback
which would be registered with the event processor in the usual fashion.  So,
a program capable of accepting an object of (say) XClass would have already
registered the construction callback XClassConstruct with its Event processing mechanism.

--
===================================================================
David Masterson					Consilium, Inc.
uunet!cimshop!davidm				Mt. View, CA  94043
===================================================================
"If someone thinks they know what I said, then I didn't say it!"

rdavis@oracle.com (Richard Davis) (11/18/89)

> richard@pantor.UUCP (Richard Sargent) says:
>
> "The object can reconstruct itself from the byte stream" requires
> that the object already exist. It still seems to me that you *have*
> to have a case statement somewhere which knows about all (interesting)
> object classes. The cases create each new type of object, probably using
> a class constructor which has a ByteStreamRepresentation argument.
> The created object is then added into the receiving program's
> organization. How to do this from a general purpose class library
> without encoding knowledge of the application is another (lesser)
> problem.

Actually, it presents no more of a problem (and no less of one :-)
than the bootstrapping problem of loading a disk operating system from
disk.  The ByteStreamRepresentation needs to contain a meta-represen-
tation (yuck) of the structure of the object to be created, which can
be parsed by the constructor on the receiving end.


Richard Davis                      Internet: rdavis@oracle.com

peterson@choctaw.csc.ti.com (Bob Peterson) (11/20/89)

In article <CIMSHOP!DAVIDM.89Nov15101037@uunet.UU.NET> cimshop!davidm@uunet.UU.NET (David S. Masterson) writes:
>
>Based on previous discussions within these groups and some work I am currently
>doing, I'd like to get some comments (please post) on the following ideas for
>the shipment of C++ objects between processes (and, by implication, the
>persistence of the object).
>
  You really should visit a library and review the last few proceedings of
relevant conferences and workshops, e.g., ACM OOPSLA Conferences since
1986, the OODB Workshops (one in '86 in California, and a second in '88 in
Germany), and recent ACM SIGMOD Conferences.

>2.  Assume each class of objects has methods for building a shippable byte
>array representation of the object and returning a pointer to that shippable
>form.
>
>3.  Assume each class of objects has methods for filling (or constructing)
>itself from the shippable byte array representation made in (2).
  Seems to me that much of this code should be encapsulated in a
translation class, with an object containing only a description of its
type.  The description is passed to the translation routines.  Now a class
implementor doesn't have to (again) write the same conversion routines,
but simply write a type description.  Even writing the type description
could be automated!

>7.  Memory pointers are the special case.  ...
>                Basically, the value of the memory pointer would be given to
>the symbol table which would return a symbol for that memory pointer (either a
>new one or the previous one).
>
  This assumes that a memory address is constant over the life of the
program.  Is this a valid assumption?  For example, a String class might
reallocate storage if a string changes size, resulting in a different
memory address for what, logically, is the same entity.  Sending the same
object twice should result in the same destination structure, without
orphaned storage, regardless of reallocations that may happen. If a
different memory address results in a different symbol the receiving end
can't recognize that the original value is no longer needed.
  How do you prevent your transfer mechanism from shipping senseless
values, i.e., values that make no sense to the receiving process? Examples
might be a window object, or an I/O buffer, or a hash table maintained as
redundant data purely for performance reasons.
  These and other identity issues are discussed in the paper, "Object
Identity," by Khoshafian and Copeland in the _OOPSLA '86 Conference
Proceeedings_ (published as the November 1986 (Volume 21, Number 11) issue
of ACM SIGPLAN Notices), page 406.  This article is a good discussion of
the identity issue.


>===================================================================
>David Masterson					Consilium, Inc.
>uunet!cimshop!davidm				Mt. View, CA  94043
>===================================================================
>"If someone thinks they know what I said, then I didn't say it!"

    Bob

Bob Peterson            Compuserve: 70235,326        Expressway Site,
Texas Instruments       USENET: peterson@csc.ti.com   North Building,
P.O. Box 655474, MS238  (214) 995-6080                 2nd Floor,
Dallas, Texas, USA 75265                                CSC Aisle C3

kipp@warp.sgi.com (Kipp Hickman) (11/21/89)

To eliminate the ``switch'' implied by the object reconstruction mechanism,
all you need is a dictionary.  The key is the tag which identifies the object
in its byte stream form (a string works nicely).  The value is a pointer to
a function to perform the reconstruction.  Usually, the function is encode
thusly:

		void (*reader)(ObjectReader& source, void* where);

The "source" argument specifies the source of the byte stream, and provides
operations to retrieve data (could be a stream, for instance).   The "where"
argument provides an (optional) address where the object should be placed,
for the cases where the object is imbedded, and shouldn't allocate its
own memory.  In C++ 2.0, you implement the above function as follows:

		void FooReader(ObjectReader& source, void* where)
		{
			Foo* f = new(where) Foo(source);
		}

Lots of details left as an exercise to the reader... :-)

					kipp hickman
					silicon graphics inc.

david@hp-ses.SDE.HP.COM (David McFadzean) (11/24/89)

kipp@warp.sgi.com (Kipp Hickman) writes:

> To eliminate the ``switch'' implied by the object reconstruction mechanism,
> all you need is a dictionary.  The key is the tag which identifies the object
> in its byte stream form (a string works nicely).  The value is a pointer to
> a function to perform the reconstruction.

This solution does indeed eliminate the switch,
but it doesn't eliminate the problem:
how does the receiving process know what to put in the dictionary?

The dictionary has to be initialized with all interesting
classes (and their corresponding keys) before any objects can
be reconstructed. If a new class is added to the common library,
the code for the receiving process has to be updated to add
the new class to the dictionary. (not much different than adding
a new case to a switch statement)

Is there any way for the sending process to tell the receiving
one which classes of instances are coming down the wire?

David McFadzean
HP Calgary Product Development Centre

davidm@uunet.UU.NET (David S. Masterson) (11/28/89)

In my previous article, I requested comments on an idea for shipping objects
between processes.  Having had a little time to play with the idea, I have
found a flaw in the methodology.  The problem concerns container classes of
virtual objects and that a receiving process would not know what type of
object was contained within the container it was requested to reconstruct.
The wish is that the container class should only know about the base virtual
object that it might contain -- not any of the possible derived children.
Part of my idea was based on the feeling that a receiving process, once
informed of the incoming object type, would know what to do with the incoming
stream.  The virtualness of internal objects in the stream means there are
more decision points than this idea could handle.

Oh well, back to the drawing board...

...maybe extending the event callback methodology for both internal and
external events...   `:-/

--
===================================================================
David Masterson					Consilium, Inc.
uunet!cimshop!davidm				Mt. View, CA  94043
===================================================================
"If someone thinks they know what I said, then I didn't say it!"

scc@cl.cam.ac.uk (Stephen Crawley) (11/30/89)

> kipp@warp.sgi.com (Kipp Hickman) writes:
> > To eliminate the ``switch'' implied by the object reconstruction 
> > mechanism, all you need is a dictionary.  The key is the tag which 
> > identifies the object in its byte stream form (a string works nicely).  
> > The value is a pointer to a function to perform the reconstruction.
> 
> This solution does indeed eliminate the switch,
> but it doesn't eliminate the problem:
> how does the receiving process know what to put in the dictionary?
>
> The dictionary has to be initialized with all interesting
> classes (and their corresponding keys) before any objects can
> be reconstructed. If a new class is added to the common library,
> the code for the receiving process has to be updated to add
> the new class to the dictionary. (not much different than adding
> a new case to a switch statement)
>
> Is there any way for the sending process to tell the receiving
> one which classes of instances are coming down the wire?

How about this?

Let us assume that objects have globally unique identifiers, and that the 
object architecture allows a program to locate an object given its id. Now 
make type tag passed in a serialised object the id for the object that 
represents its type.  If the receiving end has the appropriate object 
reconstructor in the local dictionary, fine.  If not, it can located via the 
respective type object and fetched into the dictionary using the normal object 
transmission mechanism. You only need to make sure that the local dictionary 
is started up with a reconstructor for type objects.

-- Steve