/*****************************************************************************/
/** M. JENKINS and D. CHESTER, U. Delaware -- format: plain text            **/
/*****************************************************************************/

 		 Encapsulation in a Combined Logic and 
		 Object-oriented Programming Framework 


   		  Marcelo Jenkins      Daniel Chester  
 		(jenkins@udel.edu)   (chester@udel.edu)
   	   Department of Computer and Information Sciences 
			    103 Smith Hall
			University of Delaware 
			Newark, Delaware 19716 
				U.S.A.


INTRODUCTION

It has been argued that encapsulation is one of the three main features that 
must be supported by object-oriented programming (OOP) languages [BGM89].
Encapsulation clusters the notions of data representation and operation 
set into a single program entity, where both the data and operation 
implementations of a capsule are hidden from other program entities. 
Unfortunately, logic programming (LP) languages, and Prolog is no exception, 
do not provide the necesary encapsulation mechanism needed to support 
modularity, a key software engineering technique for ``programming in the 
large''. A careful combination of OOP and LP must provide an encapsulation 
mechanism that supports the modularity capability absent from conventional 
LP languages. In this paper we discuss a particular way of incorporating 
an encapsulation mechanism into a combined logic and object-oriented 
programming (LOOP) framework. Our work is based on LOGIN [AN86], a 
first-order typed extension of Prolog that replaces conventional first-order 
terms by record structures called psi-terms, that represent types, arranged 
in a multiple inheritance hierarchy with inheritance integrated into the 
unification process. We show an approach to design an encapsulation mechanism 
for LOGIN that renders a logic language that allows the user to build large 
software applications out of encapsulated program pieces, the way it should 
be in OOP. 


PROBLEM DESCRIPTION

The only permissible access to a capsule's data representation is through 
its set of operations, called its interface. Encapsulation entails the notion 
of message passing, that is, capsules respond to messages (possibly from 
other capsules) by performing one or more operations in their interface.
Thus, other program components have an operational (or behavioural) view of 
the capsule that allows a change in its internal representation without 
altering other parts of the program, a key capability in achieving modularity.
This is true only to a certain extent given that a change in the 
implementations of a class might require a change in the implementation of 
some of its subclasses.  

Capsules are used to represent both classes and instances of classes. A
capsule consists of a data set and an operation set both of whose
implementations are concealed from other capsules. An important question
when combining LP and OOP is how to represent capsules in an LP language.
For reasons whose justification is out of the scope of this paper, we
prefer the term-representational approach of languages like LOGIN, over the
assertional approach used in languages such as O-OP [Page89] and McCabe's
class-template language [McCabe90].

In LOGIN capsules can be represented using psi-terms. However, encapsulation 
is absent because the data and operation sets of a class are not clustered, 
that is, the instance methods are not associated with the instance variables.
Consider the following example: information for people consists of their
last name, and age. Also, John is a person and a person is a teenager if
his/her age is between 13 and 19. One possible representation of this 
information in LOGIN is 

     person = (last => string; 
               age => integer).  
     john = person(last => 'smith'; 
                   age => 19).  
     teenager(P:person(age => Age)) :- Age>=13, Age<=19.

A query for this program might be

     ?- teenager(john)
     yes
 
Suppose we decide to change the representation of class person as follows 
 
     person = (last => string; 
               age => (years => integer)).
     john = person(last => 'smith'; 
                   age => (years => 19)).  
 
Now the method teenager/1 also needs to be changed as follows
 
     teenager(P:person(age => (years => Age))) :- Age>=13, Age<=19.
 
Hence, since teenager/1 does not belong to the class person, a change in one 
component of the program forces changes in other parts of the program, a 
violation of the encapsulation principle that seriously hampers modularity.   


PROPOSED SOLUTION

One way of solving this problem is to cluster the data and operation sets of a
capsule into a single program entity that localizes any changes in either one. 
This can be achieved by attaching the instance methods of a class to special 
fields of the psi-term representing the class, where the head of the clause 
is used as the name of the field and the body as its value. For example, the 
method teenager/0 can now be associated the class person as follows 
 
     person = (last => string; 
               age => integer;  
               teenager => age>=13, age<=19.). 
     john = person(last => 'smith'; 
                   age => 19).  
 
making unnecesary the use of the first (and only) argument by using it as the 
receiver of the message. This entails the notion of `self' commonly found in 
OOP languages as any instance can use the special identifier Self within the 
body of one its methods to send a message to itself. Message passing is 
performed by unifying the message with the field name and executing the body 
of the clause in the usual Prolog style. Several clauses for the same predicate
can be defined and they are tried from top to bottom by the usual Prolog 
backtracking strategy. Thus, we can write queries using a notation that 
reflects better this message passing interpretation of queries. For example, 
a trace of the resolution for the massage `john << teenager' looks like
 
     ?- john << teenager
        john.age >= 13, john.age <= 19.
        john.age <= 19.
        nil
     yes
 
where the dot notation here denotes the regular field selection operator.
Multiple inheritance is preserved as the resolution strategy tries to prove 
the message in the superclass of person upon failure to prove in it. With 
this new mechanism only methods associated with the class itself are allowed 
to directly access its data representation, hence, any change in the data 
representation is localized to the class itself. 

This procedural attachment mechanism follows the ideas found in frame systems  
[BW77]. However, the major disadvantage of these systems is the lack of a 
clear semantics for the languages. Currently we are working on formaly defining
the operational semantics of the language and then we will concentrate on 
providing the model-theoretic semantics defined in terms of a possible-worlds 
semantics that provides meaning for of a new update operator `<-', currently 
absent from LOGIN, that allows the instance methods to change the values of 
the instance variables, thus supporting objects with a persistent and mutable 
state. For example, we may add a method changeAge/1 to update the age of a 
teenager, as follows

     person = (...
               changeAge(NewAge) :- Self << teenager,
                                    age <- NewAge. ; 
               ...).
 
and after evaluation of the query 
 
     ?- john << changeAge(20) 
     yes

the age field of john has value 20.


REFERENCES

[AN86] H. Ait-Kaci and R. Nasr. "LOGIN: A logic programming language with 
       built-in inheritance". Journal of Logic Programming, 3(3):185-215,1986.

[BGM89] G. Blair, J. Gallager, and J. Malik. "Genericity vs inheritance vs 
       delegation vs conformance vs...". Journal of Object Oriented Programming
       2(5):11-17, Sep/Oct 1989.

[BW77] D. Bobrow and T. Winograd. "KRL a knowledge representation language".
       Journal of Logic Programming,3(3):185-215, 1977.

[McCabe90] F.G. McCabe. "Logic and objects". Imperial College, London, 1990.

[Page89] T.W. Page. "An Object-oriented Logic Programming Environment for 
       Modeling". PhD thesis, University of California at Los Angeles, 1989.
