The language DLP
The language DLP may be regarded as an extension of Prolog with
object declarations and statements for the dynamic creation of objects,
communication between objects and the assignment of values to non-logical instance
variables of objects.
Object declarations
Object declarations in DLP have the form
\dlpindex{object}
\oprog{object}{
object name {
var variables.
clauses
}
}
Both object and var are keywords.
The variables declared by var are non-logical variables that
may be assigned values by a special statement.
Objects act as prototypes in that new copies may be made by so-called
new statements.
Such copies are called instances.
Each instance has its private copy of the non-logical variables of the declared object.
In other words, non-logical variables act as instance variables.
Dynamically, a distinction is made between active objects and passive objects.
Active objects must explicitly be created by a new statement.
Syntactically, the distinction between active and passive objects
is reflected in the occurrence of so-called
constructor clauses in the declaration for active objects.
Constructor clauses are clauses of which the head has a predicate name
identical to the name of the object in which they occur.
Constructor clauses specify an object's own activity.
The other clauses occurring in an object declaration may be regarded as method clauses,
specifying how a request to the object is handled.
Passive objects only have method clauses.
Statements
DLP extends Prolog with a number of statements for
dealing with non-logical variables, the creation of objects
and the communication between objects.
These statements may occur as atoms in a goal.
Non-logical variables
For assigning a term t to a non-logical variable x
the statement
\dlpindex{\assignexpr}
<>-
is provided.
Before the assignment takes place, the term t is simplified.
The non-logical variables occurring in t are replaced by their current values.
In fact, such simplification takes place for each goal atom.
DLP also supports arithmetical simplification.
\nop{
For accessing the value of a non-logical variable x of some object O
a term of the form
[]
is used.
This term is simplified to the value of that non-logical
variable when the atom in which it occurs is evaluated.
}
New expressions
For dynamically creating instances of objects the statement
\dlpindex{\newpassiveexpr}
<>-
is provided, where c is the name of a declared object.
When evaluated as an atom, a reference to the newly created object
will become bound to the logical variable O.
For creating active objects the statement
\dlpindex{\newactiveexpr}
<>-
must be used.
The activity of the newly created object consists
of evaluating the constructor goal ,
where c is the object name and denote the actual parameters.
The constructor goal will be evaluated by using the constructor clauses.
Actually, the expressions and
will be simplified to a reference to an object when they occur as a term in a goal.
Both the statements introduced above
may be regarded as special cases, in which the new expressions occur in a unification goal.
Method calls
A method call is the evaluation of a goal by an object.
To call the method m of an object O with actual parameters
the statement
\dlpindex{\methodcallexpr}
<>-
must be used.
It is assumed that O is a logical variable referring to the object to which
the request is addressed.
When such an atom is encountered, the object O is asked to evaluate the
goal .
If the object to which the call is addressed is willing to accept the request then
the result of evaluating will be sent back to the caller.
After sending the first result, subsequent results will be delivered
whenever the caller tries to backtrack over the method call.
If no alternative solutions can be produced the call fails.
Active objects must explicitly interrupt their own activity
and state their willingness to accept a method call by a statement
of the form
\dlpindex{\acceptexpr}
<>-
which indicates that any request for one of the methods
will be accepted.
The computation model of DLP
The computation model of DLP combines the computation model underlying
Prolog and the model underlying a parallel object oriented language.
Parallel object oriented processing must support objects,
processes and communication between objects.
Objects
contain non-logical data, persisting during the life time of the object,
and clauses defining the functionality of the object.\nop{
The clauses are identical to ordinary Prolog clauses,
except for the possible occurrence of special atoms for creating
new objects or for communicating with other objects.
}
Objects may be active or passive.
The activity of an object is defined by so-called
constructor clauses that describe the own activity of an object.
Apart from constructor clauses, active objects may also contain so-called
method clauses that are used when the object receives a method call.
A method call is simply the request to evaluate a goal.
Processes
are created when creating a new active object
and for the evaluation of a method call.
The process executing the own activity of an active object is called
the constructor process.
For each method call a process is created to enable backtracking
over the results of a method call.
Passive objects have no activity but answering to method calls.
Active objects must explicitly interrupt their own activity to indicate the willingness
to answer a method call.
Communication
with another object takes place by engaging in a (synchronous) rendez-vous.
In order to achieve compatibility with the ordinary Prolog goal
evaluation, DLP supports
global backtracking over the results of a rendez-vous.
With respect to backtracking,
it is transparent whether a goal is evaluated remotely,
by another object or locally,
provided the necessary clauses are defined.
This transparency holds for both passive and active objects.
Below is pictured what happens when a process issues a method call
to an active object.
Here we assume that accept statements may occur only in the constructor process
associated with an (active) object.
.so sv
As soon as both the process calling the method and
the constructor process of the object to which the call is addressed have
synchronized, the activity of the constructor is interrupted and a
process is created to evaluate the goal .
The constructor is interrupted for safety reasons, in order to guarantee
that no other method call will be accepted.
The calling process waits for an answer.
As soon as the caller has received a result, both the calling process and the constructor
process resume their activity.
On backtracking, the calling process may ask for alternative solutions.
Passive objects allow unlimited internal concurrency:
in other words, an indefinite number of method calls may be active
simultaneously.
For active objects, mutual exclusion is provided
to the extent that when a particular method call is accepted
no other method call will be accepted
until the first answer for that call is delivered.
This protocol of mutual exclusion seemed more
natural than either locking out the object until all
answers have been delivered or providing no mutual exclusion at all.
An example
As an example, consider the object declaration for a travel agency.
\lprog{agency}{
.ds agency.pl
}
A travel agency may be asked for a destination.
The destinations an agency offers are contained in a list of cities.
The non-logical variable cities storing this list is initialized
to contain as possible destinations amsterdam, paris and london.
Creating a new agency, and subsequently asking it for a destination, is
done as in the following goal.
?-
O = new(agency()),
O!destination(Y),
...
When evaluating the first component of this goal
the logical variable O will become bound to the newly created agency that offers
as destinations amsterdam, paris and london.
Immediately thereafter the method call will be evaluated,
but the call will not be accepted until
the accept statement expressing the willingness to accept a call is reached.
The evaluation of the method call will result in binding Y to amsterdam
and when backtracking occurs, subsequently to paris and london.
Then the call will fail.
Backtracking over a new statement is not possible.
This call will simply fail.
\nop{
And parallelism
As an additional primitive DLP offers an and-parallel operator.
The goal
?- O!destination(tokyo) & O!add(tokyo)
will result in concurrently requesting the object O to check
for the destination tokyo and to add tokyo as a destination.
Due to the mutual exclusion between method calls, since an agency is an active object,
one of the calls will be accepted first and exclude the other until it has
produced a result.
So the goal above may either fail or succeed, depending on whether the request
for adding a destination is granted first.
}
Inheritance
An essential feature of the object oriented approach is the use of inheritance
to define the relations between objects. C.f. [We87], [WZ88], [HOB87].
Inheritance may be conveniently used to factor out the code common
to a number of objects.
For an untyped language, as DLP, inheritance is a facility to share code.
The declaration for an object inheriting from an object base
is
\dlpindex{inheritance}
\oprog{inheritance}{
object name : base {
var variables.
clauses
}
}
This declaration will result in adding the non-logical variables and clauses declared
for the object base to those of the declared object.
Any non-logical variables of the base object that occur also in the declared object
will be overwritten by the non-logical variable of the declared object.
This will be of significance only when at least one of the non-logical variables
has an initializing declaration.
Such overwriting does not take place for clauses.
When the declared object contains clauses similar to
clauses in the base object, concerning the same predicate,
then these will be treated as alternative choices for evaluating an atom.
As an example, consider the relation between a researcher and a professor,
stated in the declaration below.
\lprog{researcher}{
object researcher {
var field.
knowsof(X):- member(X,field).
}
object professor : researcher {
knowsof(X):- committee(Conference,X).
}
}
The intended meaning here is that a professor knows of the topics of the
conferences for which he has been a member of the program committee,
in addition to what he knows of as a researcher.