Communication over channels
The idea originally proposed in [ST83],
to implement object oriented programming by continuously running processes
receiving a stream of messages,
has been a starting point for a number of object oriented
extensions of Concurrent Prolog and Parlog. Cf. [Da89].
A similar idea is embodied in Delta Prolog. [PN84]
Our proposal resembles the one given in [PN84],
although there are some important differences.
Before going into details we will present the language constructs involved.
First of all we need a facility to create processes.
We will use a goal of the form
to create an active instance of the object c.\n
For creating new channels we use a goal of the form
- that results in binding the newly created channel
to the logical variable C.\n
Further we need, what we call an output statement of the form
for C referring to a channel and t an arbitrary term.\n
Also, still following CSP terminology, we need an input
statement of the form
where C is assumed to refer to a channel and t an arbitrary term.
We will characterize the semantics of communication over
channels by giving a simple
example, adapted from [PN84],
but originally given in [ST83].
Assume that we wish to implement a counter,
that allows us to ask for its value and to increment
its value.
Clearly we must have some means to store
the state of the object,
and also some means to send it the corresponding messages.
With the constructs introduced,
our implementation looks as follows.
XX
The first clause encountered is the constructor for an instance of ctr.
The argument C is assumed to be referring to a channel.
Evaluating the constructor results in calling
, initializing the (logical) state variable holding
the value of the counter to zero.
The remaining two clauses define the body of the object.
The first clause contains the input statement
that is used to answer requests for the value of the counter.
The second clause contains the input statement
that is used to increment the value of the counter.
The actual value of the counter is maintained in a proper
way by passing it as an argument
to the tail-recursive call to run.
A typical example of the use of such a counter is the goal
XX
that effects the binding of X to one.
The example given illustrates the use of such objects to
implement server processes.
Let us now give a more detailed description of the semantics
of communication over channels.
Communication over channels is synchronous,
in that either side waits until there is a complementary
communication intention for that channel.
For the example above this means that the body of the counter
will stick to the gola
until the user process reaches
,
or reversely the goal must wait until
is reached.
We call a communication successful if the term at the input side,
or more briefly the input term, is unifiable with the
output term, the term at the output side.
When these terms do not unify, as is the case for
and , the input side is allowed to backtrack
until it finds another input statement for that channel and the procedure is repeated..
As long as the input side is backtracking the output side waits
with its request to communicate.
The assymetry with respect to backtracking is sufficiently
motivated by the example above.
We must remark however that Delta Prolog adopted a communication mechanism
that is symmetric in its backtracking behavior,
and rather complex to our mind.
We stress the fact that both in Delta-prolog and in our proposal
communication over channels is bi-directional,
in the sense that variables both in the input term and the
output term may receive a value through unification.
As an example consider the following object declaration
object a {
a(C):- run(C,0).
run(C,N):- C?f(N,Y), run(C,Y).
}
and the goal
} :- C = new(channel), new(a(C)), C!(X,1).
which results in binding X to zero and Y in the body of a to one.
We conclude this intermezzo with an example of a situation
where the number of processes can grow indefinitly large.
Below we present our implementation of the solution to
generating primes given in [Ho78].
YY
As sketched here, communication over channels
offers a rather limited functionality.
In particular since we have not included
guarded commands or annotated variables,
synchronization must relie purely on the synchronous
nature of communication.
Another important limitation is that
no backtracking over the results of a communication is
allowed,
once a successful communication is achieved.
a------------------
In the previous section we have seen how we may implement
objects with states without the use of non-logical variables
to store the state of such objects.
The approach sketched there
knew a number of limitations.
Instead of augmenting the proposal of the previous section,
we will take up the main thread of this chapter
and will investigate how we may achieve
object oriented behavior by regarding clauses as methods.
Below we summarize the language extensions that we treat in this
section.
- - to assign the value of a term to the non-logical variable x
- - to create an active instance of c, to which O will refer
- - to call the method m of the object to which O refers
- - to state the willingness to accept calls for
Nota that we restrict ourselves to active objects. KK
States
As we have indicated