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

RE: Loosing abstraction due to non-alting channels

Gerald et al.

> I am worried about the following. Java is an object-oriented programming
> language and one advantage of object-orientation is that it can help us to
> reuse code (classes).

The re-usefulness of OO should definitely be open for debate ... :-)

>                       I use this all the time. A problem with distinct
> *2*Channel specifications at the input/output interfaces of reusable classes
> is that these input/output interfaces can easily conflict with each other
> (i.e., channel input/output interfaces do no match) that makes reusing code
> (without modifying the code) impossible. For example, in Marcel's example
> above One2OneChannel and Any2OneChannel channels are both valid channels,
> but once One2OneChannel is declared at the input/output interface of process
> A or B then these processes cannot be reused in an Any2OneChannel scenario,
> or am I wrong about this? I don't know if the class/interface hierarchy of
> the JCSP channels take this into account, but in CTJ these things are more
> relaxed.

I'm getting ever more cynical about the merit of inheritance :-(.  For example,
the obvious inheritance network for the JCSP channels would be:

                      ________/              \________
                     /                                \
              Any2OneChannel                     One2AnyChannel
                     \________                ________/
                              \              /

except that that, of course, is an inheritance *graph* and Java only allows
inheritance *trees*.  The same problem arises in the natural shadowing of
the java.awt class hierarchy by the jcsp.awt classes.  Each one of these
extends (in the Java sense) its shadow from java.awt - which seemed the
*proper* OO thing to do.  But that also means that there is no class hierarchy
between the jcsp.awt components themselves (and lots of code had to be
cut-and-pasted).  There seems no way out of this - we can't complete
a commutative diamond of class inheritance.  So, I'm wondering how much
we really should try living with this concept ...

For the JCSP channel classes, we could have abandoned one of the inheritance
links in the above - but which?  Much better was to abandon them all:

  One2OneChannel   Any2OneChannel   One2AnyChannel   Any2AnyChannel

which is what we did ... :-) :-) :-)

This results is a much simpler scheme.  These classes are what the network
builder instances.  We choose the appropriate variety and build our network.
There is no need for replacing a One2OneChannel (say) with an Any2OneChannel
that calls for an inheritance mechanism.  If I'm extending (not in the Java
sense) a network by adding some writers that wish to share a One2OneChannel
previously written to by just one, I have to rewite the network code (i.e.
the Parallel construct) anyway - so redeclaring the channel to be Any2One
is no problem.  I can't see how class inheritance would help in any way -
it would be at best irrelevant and at worst a hindrance (e.g. by adding
unnecessary run-time overhead)?!!

There may be a misunderstanding going on.  When we define a JCSP process,
the channel declarations in its constructor(s) or set methods should not
be any of the above concrete classes (which specify cardinality) but should
be one of the interfaces (or abstract classes):

  ChannelInput, ChannelOutput or AltingChannelInput

If we used a concrete class (e.g. One2OneChannel), this does two bad things.
First, it enables us to read *and* write to the channel - which would always
be an implementation error.  [Note: this happens in occam and has long been
an irritation.  At least, though, the channel usage checker would jump on you!]
Second, we run into Gerald's problem - namely that the so-defined process
could only be used in a network that supplies a One2OneChannel and could not
be applied in a network that has multiple writers for that channel.

But we don't do that!  We just specify ChannelOutput in the process interface
(in the CSP/occam sense of interface).  All this does is say that the process
will be outputting to that channel and that it will be outputting Objects.
[Note: if we specify ChannelOutputInt, the only difference is that it will
be outputiing ints.]

Such a process may be used in *any* network.  If it's the only writer, plug
it into a One2OneChannel.  If it's one of several writers, plug it into an
Any2OneChannel.  The process doesn't care what it's plugged into - it can
be reused in any scenario - and we haven't used inheritance ;-) ;-) ;-)

I'm sure CTJ has the same scheme - i.e. you declare process interfaces with
Java *interfaces* (or *abstract classes*) for the channels, not Java (concrete)
*classes*, and where the Java *interfaces* restrict the process implementation
to either input or output (not both).  In fact, I remember Gerald teaching me
just how to do this during (or immediately after) the WoTUG-20 conference back
in April 1997 when my understanding of these things was distincly wobbly!