[comp.sys.amiga.tech] Object Oriented IPC -- Some reservations

shf@well.UUCP (Stuart H. Ferguson) (07/15/88)

Pete Goodeve (pete@violet.berkeley.edu) writes long and thoughtfully
about OOIPC and how it doesn't fit well for the kinds of things he wants
to do.  As official spokesman for OOIPC (:-)), I'll try to address his
misgivings. 

| I find I'm basically uncomfortable with the "Method/Object" concept as
| a general-purpose metaphor for IPC.  This is partly perhaps because I
| always HAVE been comfortable with the idea of independent processes
| synchronized by messages passed between them (dating from well before the
| Dawn of the Amiga, I should add).

OOIPC is not intended as a general-purpose metaphore for IPC.  The Amiga 
already has a general-purpose metaphore -- the Exec paradigm of messages
and ports.  For many applications, such as task synchronization with
semaphores, the simple Exec metaphore works just fine.  OOIPC does not
address the entire problem of interprocess communication, just a 
relatively small but important part.

OOIPC is targeted at the "Integrated Environment" problem that arises in
a workstation-like tool like the Amiga.  Although integrated
environments like super-charged compilers with built-in editors and
debuggers are nice and fast, the tools they provide are perhaps not the
best, but cannot be changed because they are integral with the
program.  The Amiga, with multi-tasking and a low-overhead
general-purpose IPC mechanism, makes possible a kind of integrated
environment built not as a single monolithic program, but out of
smaller, more general tools.  The challenge, therefore, is to design a
Standard Integrated Tool Environment whereby many tools can live and
work in harmony and operate more or less as a single unit. 

Probably calling it IPC is a mistake.  It should probably be called
something else. 

| Most of the objections here, though,
| arise from trying to figure out how one might implement the "slideshow"
| processes I used for my demo, if the OOIPC protocol were used.

Interesting that you should say this, Pete, as this is in fact exactly
what I'm doing.  I was very impressed with the demo PPIPC slide-show
system and set about to reproduce it using OOIPC.  I've been able to do
it so far with a good deal of success, I think.  This is not an off the 
wall description here -- I've actually done it and it (pretty much)
works. 

The first major hurdle was deciding how to divide up the problem so that 
it takes the required form -- that of autonomous objects responding to 
commands.  The central object class in a slide-show program is the
BitMap class.  The object structure I chose contains a bitmap struct,
colormap and viewmode as a minimum.  Objects can also have optional
attributes, and some of those are used in describing special properties
that a bitmap can have.  For example, an optional SCRN attribute can be
attached to an object and contains a pointer to an Intuition
CUSTOMBITMAP Screen. 

I've written servers to load, delete and display Bitmap objects, as well 
as a server which attaches a behavior to Intuition events on a displayed 
bitmap.  All of this is totally generic and could be used by any server
wanting to manipulate bitmaps.  The only part of this which was a little
dicey is the Monitor method, but I think I've got that licked.  The
problem was how to make a bitmap sensitive to mouse clicks in a general
way while still keeping it an "object," and not inextricably intertwined
into the application for which it's being used.  My solution was to
define a method on displayed bitmaps which configures *the bitmap* so
that it performs certain actions when it receives of Intuition events. 
These actions are to send commands to other objects. 

There's one more object in the system -- the slide-show object.  A
slide-show object has a structure containing a filename and a bitmap
object for each frame of the show.  Some of the bitmaps will be in
memory and one of the ones in memory will be displayed.  When it
displays a bitmap, the slide-show server also applies the Monitor method
to make the bitmap respond to mouse clicks.  When the user clicks on one
side of the bitmap, it will sense this and send a Forward message to the
slide-show object.  When the user clicks on the other side, the bitmap
will send a Backward message.  Viola -- the required feedback loop which
also permits other types of control, via, say, a joystick client. 


| In the OOIPC system as currently envisaged, each server must "register" all
| the method/object pairs it can service.  This means that all servers must
| be started up beforehand -- there seems to be no mechanism to load a server
| on demand.  [It's true that this is also the case with the current early
| revision of PPIPC, but the LoadIPCPort command I discussed is intended to
| cover this, and the user-supplied file pairing ports and servers that would
| be needed to implement it is a lot simpler for him/her to handle than a
| similar (though doubtless much longer) list of method/object/server
| associations.]
 
| In passing, it seems that a lot of overhead goes into making it possible to
| change services (for a particular object/method pair) on the fly.  Maybe
| I'm not thinking of the right applications, but I can't see this feature
| being needed much.  [PPIPC handles the same sort of situation simply by
| changing the Server on a Port.]

These two are actually related, the latter making the former possible.  
It is possible under the OOIPC currently envisaged to have servers load 
on demand, not as an extension of the library but in fact as a 
consequence of the basic design.

You do it like so:  Write a "super-server" program which acts as a kind 
of front end for unloaded servers.  The program reads from a file and
registers a bunch of services that it doesn't really service, but that
it knows who can.  When a client makes a request for a non-loaded
service, the request gets routed to the super-server.  The super-server
can then load the actual server and pass the message along.  When the
actual server starts up, it will register itself, and the services it
registers will override the services registered by the super-server so
that all subsequent requests go directly to the actual server.  The
super-server could unload servers by just signaling them with control-C
(under low-memory conditions, for example), and then requests would
revert to being sent to the super-server again. 

This approach has several advantages.  It's not built-in to the IPC
system so developers can write their own super-servers to fit their own
needs.  Also, it's transparent to client and server programmers (as it
should be) -- no explicit "Load" call need be made -- and servers can be
resident or loadable by user preference to tune performance with no
modification to clients or servers. 

There are a few difficulties with the approach, specifically with 
startup and shutdown.  How does the super-server know when a new server
has started up and it ready to receive messages?  There's no explicit
mechanism for checking this under OOIPC, although I suppose a reasonably
general one could be added.  A more serious problem is how does the
super-server decide when to shutdown a given server?  Since there is no
explicit count of clients as there is in PPIPC, there is less
information about what servers are reasonable to shut down. 


| I foresee problems with things like Inheritance if things aren't set up
| exactly right.  [example of things going wrong...]

Well, this would certainly be an example of something breaking because 
of inheritence, but then again, things will always break if you push on
them hard enough.  The purpose of inheritence is to extend existing
classes without having to re-implement already working methods.  The 
rules for creating a subclass are that it has to be just an extension of 
its super-class so that old methods will still work.  If an old method 
will not work on a subclass then it should be overridden by a method 
supplied specifically for the subclass.

In the example given of the FILE - IFF - ILBM class hierarchy, you 
probably wouldn't want to override the reading method when creating each 
subclass.  You might want to read and IFF as if it were a FILE for 
example, so you could call the different methods FILE/READ, IFF/RIFF, 
and ILBM/RDBM.  This would allow you to READ an ILBM as if it were a 
file, RIFF it as if it were an IFF, or RDBM it like a bitmap.

Just some suggestions.

| By the way, how DO you intend to specify things like filenames?  [...]
| In PPIPC you just use a suitable item
| ('IFFP' say, instead of 'FILN') and the server will do the necessary.  

It's sort of the same under OOIPC.  Commands have arguments, tagged by 
identifiers, and the server looks at those to decide what to do just 
like PPIPC.  Using `IFFP' and `FILN' would be perfectly suitable 
arguments id tags for a `READ' method.  The arguments are attached to 
the command, not the object, and are an integral part of the message, 
like IPCItems under PPIPC.


To the Root Problem:
| In my
| mind, the concept "Object-Oriented" evokes expectations that don't seem to
| translate well to InterProcess Communication.  It's true for instance that
| Object-Oriented language people talk about "Sending Messages to Objects",

Hmmmm.  OOIPC should not be confused with Object-Oriented Programming.
It is not intended to be an object-oriented programming language.  The 
"Object-oriented" part refers to the organizing principle behind the
communication that occurs between processes.  By motivating the design
with concepts derived from "object-oriented" systems, messages end up 
having not only a standard structure, but a standard *meaning* as well.  

| The OOIPC concept, too, is strongly biassed towards synchronous
| communication, which seems sort of strange for a message-based system.

Perhaps.  It's just that synchronous action is much easier to deal with 
in general than asynchronous action, so why not make that natural and 
easy to do.

| Stuart has suggested some procedure calls for asynchronous operation, but
| they don't mesh with the sort of paradigm I'm thinking of.  He suggests
| "DispatchAsync()", "CheckCmd()", and "WaitCmd()"; I assume that these are
| analogous to CheckIO and WaitIO -- 

You are correct.  That's exactly why I picked these -- because that's
what's available under Exec's device I/O.  I'm open to better
suggestions. 

| This isn't an appropriate model for multiple
| cooperating processes, with possibly lots of messages active:  

Nothing stops you from saying:

	replymask = (1L << ubase->replyPort->mp_SigBit);
	Wait (mymask | replymask);

Just like you would if you had multiple asynchronous packets under Exec
I/O. 

| It is a "two-level" system.  Clients have a very different status to
| Servers: Clients know about "Methods", "Objects", and "Dispatching";
| the concept of "Ports" and "Messages" is deliberately hidden [Stuart's
| comment elsewhere].  Servers, though, do have to know about messages and
| ports -- AND all the other stuff.

I've been working from the desire to make things easy for the client 
programmer.  My thinking has been, "There's going to be all these neat
tools people will be writing to do things to bitmaps and files and all
sorts of things.  It would be great if novice programmers could get into
the act easily and use those services without having to be experts on
ports and messages and things."  Server programmers I figure are going
to be more experienced, and can therefore deal with the underlying
structure of a Dispatch(). 

[Pete compares PPIPC and OOIPC from the programmers perspective]
| PPIPC on the other hand is strongly Asynchronous (and much more
| symmetrical vis-a-vis Clients and Servers).
  [...]
| I think that for general-purpose IPC, hiding the Port/Message mechanism
| would be a big mistake.  
  [...]
| A PPIPC example is the Script Manager for the slideshow, which only wakes
| up when it gets a signal that a message has arrived at either the request
| or reply Port (or a control-break interrupt has been typed -- they all
| signal the same Wait() statement). [...] it is a
| "Manager" -- it is WAITING for BOTH "commands" AND "responses"; there is no
| asymmetry.

I've written more or less the same program under OOIPC and it works just 
as you describe -- as both a client and a server.  It uses 
DispatchAsync() to start the loading of a bitmap, and the synchronous
Dispatch() to display and un-display bitmaps.  It also acts as a server
for the slide-show class object, causing it to advance or regress on
command, and it also responds to control-C.  It works fine.  In fact,
sometimes making requests synchronously with Dispatch() is more
appropriate because I don't need to implement an explicit state machine
to do a sequence of actions -- I just do them in order in the program.  
The only action I do asychronously is the one I need to do
asychronously: loading bitmaps into memory. 

| When you have a bunch of
| messages coming back at arbitrary times you have to have some way to
| identify them [...]  Again as an example, the Script Manager
| built an internal list of the bitmaps, with a lot of extra information on
| the current status of each; it was easy to add an item that was private to
| the Script Manager to the message ('MARK'), directly indicating the
| structure concerned.

But as I understand, other servers in this setup had to know explicitly
about the `MARK' item in order to correctly copy it from one message to
another.  If this is so, it seems less than elegant. 

You can add your own attributes to an object and put anything you want
in them (a `MARK' attribute would be just fine), and because of the way
the Object structure is designed, servers will ignore any attribute
blocks they don't recognize (for upward compatability).  This little tag
will travel around with the object wherever it goes and never needs be
looked at except by those servers (or clients) that are looking for it. 


| Leo's "DPaint" example brings up another point that he didn't mention
| (maybe because nobody but me sees it as a problem...).  A "conceptual bias"
| of mine is that I see "performing a method on an object" as a unitary,
| fixed operation: the idea of the method having a user-interactive component
| is not intuitive to me.  

I don't see why.  You would have no problem using a user-interactive
file requester, say, by calling a function in a program: 

	error = EditFilename (dir, name);

You could just as well imagine doing this as a request to a server:

	error = Dispatch (editCommand, filenameObject, NULL);

and using IPC (any IPC) you could do this asynchronously and do other
stuff while waiting for the user to figure out what file he wants. 

| I agree that there is no physical problem in the way of doing this
| with OOIPC (except that the sender would most likely have to suspend
| activities until you were done)

Not really.  The sender would just have to refrain from using whatever
data (or object) was passed in the message until the request completed,
and this is true no matter what IPC mechanism you use. 


| I think [ OOIPC is ] a
| fascinating concept that will have a lot of applications.  I get the
| feeling that we're reaching a consensus that BOTH PPIPC and OOIPC will have
| their place; all I hope is that we can get some cross-compatibility so that
| we don't each end up on our own island.

I doesn't make sense to have TWO "standards."  Either paradigm could be 
implemented as a sub-set of the other, it's just a question of which way 
is more elegant (or more Zen, as some people would say ;-).

| It strikes me that as OOIPC has a defined message structure that it
| actually sends to a server, perhaps all you need as a foundation for
| compatibility is for this itself to be in IPCMessage format.

I would suggest that the PPIPC message standard be expanded to include 
"objects" as a basic data type, rather than requiring all pointers to be 
to sized blocks of memory.  This would be a much bigger step towards 
compatability.  You were considering, Pete, adding a flag to indicate 
that an item pointed to another message, but why not make that a pointer 
to an object instead?

Objects and messages are in some ways very different.  Objects are like 
IFF files in that if a server doesn't understand something, it can 
safely ignore it.  Messages are NOT like this in that if a server
doesn't recognize some item, it should respond with an error and do
nothing.  Messages need to be self-describing in order to be processed
by "dumb" network servers.  Objects can be almost anything, since their
behavior is defined by their methods. 

|                                                        -- Pete --
-- 
		Stuart Ferguson		(shf@well.UUCP)
		Action by HAVOC		(shf@Solar.Stanford.EDU)

peter@sugar.UUCP (Peter da Silva) (07/16/88)

... and stirring up trouble ...

In article <6524@well.UUCP>, shf@well.UUCP (Stuart H. Ferguson) writes:
> Probably calling it IPC is a mistake.  It should probably be called
> something else. 

How about OO-OSE, object oriented operating system extensions.

(then my idea for procedural subsets would be local OO/OSE, and seperate
 servers are a global OO/OSE...)

> In the example given of the FILE - IFF - ILBM class hierarchy, you 
> probably wouldn't want to override the reading method when creating each 
> subclass.  You might want to read and IFF as if it were a FILE for 
> example, so you could call the different methods FILE/READ, IFF/RIFF, 
> and ILBM/RDBM.  This would allow you to READ an ILBM as if it were a 
> file, RIFF it as if it were an IFF, or RDBM it like a bitmap.

I don't like this idea. Better to set up different objects of the
appropriate type. Why would you want to do a FILE/READ on an object
of type ILBM? There isn't any meaningful place to read into.

> | I get the feeling that we're reaching a consensus that BOTH PPIPC and
> | OOIPC will have their place...

> I doesn't make sense to have TWO "standards."  Either paradigm could be 
> implemented as a sub-set of the other, it's just a question of which way 
> is more elegant (or more Zen, as some people would say ;-).

They're both Zen, but for different models. My original idea for IPC
was that you would eventually be able to write programs in it,
graphically, the way you can with UNIX pipelines. You just have your
programs that act as generators and filters and stick them together
with lines in a patch-panel sort of thing. Like if you wanted to filter
an IFF image you'd have your "ILBM" icon which reads an IFF file and
wraps it in a message and writes it to its output port. Your filter icon
would take the ILBM and do a transform on it. Your display icon would
take the ILBM and pop it up. If you wanted to edit it or save it instead
you'd pop in the appropriate icons.

It seems this would be easier with PPIPC, but it shouldn't be impossible
with OOIPC. Why don't you two guys take a crack at it?
-- 
-- `-_-' Peter (have you hugged your wolf today?) da Silva.
--   U   Mail to ...!uunet!sugar!peter, flames to alt.dev.null.
-- "Running OS/2 on a '386 is like pulling your camper with an Indy car"