One of the basic ideas of object-oriented programming is the encapsulation of data and procedures into objects. Each object belongs to exactly one class, and an object is referred to as an instance of its class. A class definition determines the following things for its objects:
All interaction with an object is by sending it messages. The command to send a message to an object has the form
Object MessageOp Message
where Object is an object, MessageOp is one of the message operators (‘<<’, ‘>>’, or ‘<-’) and Message is a message defined for the object's class. Roughly speaking, the ‘>>’ message operator is used for extracting information from an object, ‘<<’ is for storing information into an object, and ‘<-’ is for any other sort of operation.
For example, using the point class defined in the next section, it would be possible to give the following command, which demonstrates all three message operators.
| ?- create(point, PointObj), PointObj >> x(InitX), PointObj >> y(InitY), PointObj << x(2.71828), PointObj << y(3.14159), PointObj <- print(user_output), nl(user_output). (2.71828,3.14159) PointObj = point(23461854), InitX = 1.0, InitY = 2.0
First it binds the variable
PointObj
to a newly created point
object. Then, the two get messages (sent with the ‘>>’
operator) fetch the initial values of the point's x
and y
slots, binding
the variables InitX
and InitY
to these values. Next, the two
put messages (sent with the ‘<<’ operator) assign new values to
the object's x
and y
slots. Finally, the send message (sent with the
‘<-’ operator) instructs the point object to print itself to the
user_output
stream, followed by a newline. Following the goal, we see
the point has been printed in a suitable form. Following this, the values of
PointObj
, InitX
, and InitY
are printed as usual
for goals entered at the top-level prompt.
Because this goal is issued at the top-level prompt, the values of the
variables PointObj
, InitX
and InitY
are not retained after
the command is executed and their values are displayed, as with any
goal issued at the top-level prompt. However, the
point object still exists, and it retains the changes made to its
slots. Hence, objects, like clauses
asserted to the Prolog database, are more persistent than Prolog variables.
Another basic idea of object-oriented programming is the notion of inheritance. Rather than defining each class separately, a new class can inherit the properties of a more general superclass. Or, it can be further specialized by defining a new subclass, which inherits its properties. (C++ uses the phrase “base class” where we use “superclass.” It also uses “derived class” where we use “subclass.”)
SICStus Objects uses term expansion to translate object-oriented programs into ordinary Prolog. (This is the same technique that Prolog uses for its DCG grammar rules.) As much as possible is done at compile time. Class definitions are used to generate Prolog clauses that implement the class's methods. Message commands are translated into calls to those Prolog clauses. And, inheritance is resolved at translation time.
SICStus Objects consists of two modules, obj_decl
and objects
. The
obj_decl
module is used at compile time to translate the
object-oriented features of SICStus Objects. Any file that defines
classes or sends messages should include the command
:- load_files(library(obj_decl), [when(compile_time), if(changed)]).
The objects
module provides runtime support for SICStus Objects
programs. A file that sends messages or asks questions about what
classes are defined or to what class an object belongs should include
the command:
:- use_module(library(objects)).
You will probably include both in most files that define and use classes.
Please note: A file that loads library(obj_decl)
currently cannot
recursively load another file that loads library(obj_decl)
, because that would
confuse the internal database being used by the package.