$=||||||||||
Logic programming and concurrency
In section \ref{des/per/concept} we have introduced concurrent
logic programming as one of the paradigms of distributed computing.
We have also sketched how to use a concurrent logic
programming language to implement objects.
In this section we will treat two languages that provide
object oriented extensions to a concurrent logic
programming language.
.so Vulcan
.so Polka
A restriction adhering to both languages is the absence of backtracking
over the results of a method call.
As a remedy one could re-introduce backtracking by integrating
a concurrent language with Prolog. C.f. [Sh89].
Merely providing an interface between the two languages
is not satisfactory, simply because it does not provide an
integration of the two computation models underlying
these languages.
Embedding Prolog in a concurrent logic programming language,
although feasible for non-flat versions allowing
arbitrary goals in the guard, leads to
efficiency problems.
Moreover, as [Sh89] observes, the implementation techniques for
concurrent logic programming languages
lag far behind those developed for
sequential Prolog. C.f. [He86].
Another option might be to extend Prolog to a language
combining logic programming and concurrency.
An example of such an approach is the language Delta Prolog.
.so DeltaProlog
When we compare Delta Prolog with the object oriented
languages based on the concurrent logic programming
model, the most obvious difference
is that communication in Delta Prolog must be stated explicitly,
whereas communication in the concurrent logic programming
languages is mediated by shared logical variables.
Another difference is that processes created for executing a
concurrent logic program are usually fine-grained,
whereas Delta Prolog gives rise to coarse grain parallelism.
We note that Delta Prolog allows to implement objects
in a similar way as the concurrent logic programming
languages.
We do not consider Delta Prolog to be object oriented, however.
DLP
supports concurrency in basically two ways.
The first, perhaps most natural way,
is to create active objects that execute their own activity
in parallel with the activity of other objects.
The second way is to let an object evaluate a number of
method calls simultaneously.
To implement this, a notion of
processes has been introduced, distinct from objects.
Each active object has a so-called constructor process
associated with it, that handles the evaluation of the body of
the object, as expressed in the constructor clauses.
Moreover, for each method call a process is created to
handle the backtracking information needed to generate all
answers to the call, and to communicate these to
the invoking process.
When multiple processes are active for some object, we speak of
internal concurrency, or multi-threaded objects.
Passive objects allow unlimited internal concurrency.
On the other hand, for active objects we have allowed such internal
concurrency only for backtracking over alternative
answers, after having delivered the first answer.
The reason for this policy is that we wish to guarantee mutual
exclusion between method calls for the time needed
to produce the first answer.
That is to say, no two method calls
will be active similtaneously with producing their first results.
A method call may however become active when other processes
are still busy backtracking over the answers of a call.
The language DLP provides primitives for synchronous
communication over channels,
that are rather similar to those offered by Delta Prolog.
However, the backtracking that may arise during communication over
channels in DLP is much more limited
than the distributed backtracking supported by Delta Prolog,
in that it occurs locally within the confines of the process
stating the input goal.
The rendez-vous supported by DLP does not suffer from
such a restriction.
Moreover, we claim that our rendez-vous allows to
impose synchronization constraints that cannot be expressed
in Delta Prolog.
Additional parallelism may be achieved in DLP
by using the primitives for
process creation and resumption requests directly.
These constructs allow to join the results of two
independently running processes sharing logical variables.
We have not encountered any such mechanism in the literature!
We remark that these primitives have been used to
implement the synchronous rendez-vous
arising from a method call.
To enable active objects to engage in a rendez-vous
we have provided an accept statement for
interrupting the own activity and to state the willingness to
answer particular method calls.
This construct has been inspired by languages combining
the object oriented programming paradigm with concurrency.
A notable difference between DLP on the one hand and Delta Prolog
and the two object oriented languages based on the concurrent logic
programming model on the other hand is that states of objects
in DLP are kept in non-logical (instance)
variables whereas
in the three other approaches states are maintained as the
argument of a tail-recursive predicate.
We note that the conditional accept statement
introduced in section \ref{des/ext/accept}
allows a similar implementation of objects.
Objects and concurrency
A radically different approach at combining logic
programming, object oriented programming
and concurrency is to take an existent
parallel object oriented language as a starting point
and to attempt to lift it to a language supporting
logic based computation.
Such an approach is exemplified by the language MultiLog.
As another example we wish to mention the language Orient84/K.
.so MultiLog
.so Orient
Both MultiLog and Orient84/K support single-threaded objects only.
One of the possible advantages of lifting a parallel object oriented
language may be that the mechanisms for process
creation and communication are to a certain extent
available.
However, implementing a Prolog interpreter is not altogether
a trivial matter.
DLP
is, apart from a number of notational differences,
quite similar to MultiLog.
A notable exception to this similarity, however,
is that, unlike MultiLog,
DLP does support global backtracking over the results of a rendez-vous.
In a sense our language DLP may be regarded as the result of lifting
the language POOL to a logic programming language.
See section \ref{impl/comp:lang} and [Am87].
The problem we had to solve was to find the proper constructs
for process creation and communication between processes.
As a consequence, our initial design goal has been
the extension of Prolog to a parallel object oriented language.
Unlike MultiLog and the object oriented languages
based on concurrent logic programming,
we did not wish to give up compatibility with
Prolog.
DLP therefore supports the {\it don't know} non-determinism
of backtracking.