Go to the first, previous, next, last section, table of contents.


Object oriented programming

Author(s): Angel Fernandez Pineda.

Version: 1.5#118 (2000/4/19, 18:13:43 CEST)

Version of last change: 1.3#63 (1999/9/29, 19:54:17 MEST)

O'Ciao is a set of libraries which allows object-oriented programming in Ciao Prolog. It extends the Ciao Prolog module system by introducing two new concepts:

Polymorphism is the third fundamental concept provided by object oriented programming. This concept is not mentioned here since traditional PROLOG systems are polymorphic by nature.

Classes are declared in the same way as modules. However, they may be enriched with inheritance declarations and other object-oriented constructs. For an overview of the fundamentals of O'Ciao, see http://www.clip.dia.fi.upm.es/~clip/papers/ociao-tr.ps.gz. However, we will introduce the concepts in a tutorial way via examples.

Early examples

The following one is a very simple example which declares a class -- a simple stack. Note that if you replace class/1 declaration with a module/1 declaration, it will compile correctly, and can be used as a normal Prolog module.

%%--------------------------------------------%%
%% class/1, at the beginning of the file,     %%
%% will declare current source to be a class. %%
%%--------------------------------------------%%

:- class(stack,[],[]).

% State declaration: storage/1 will be an attribute.
:- dynamic storage/1.

% Interface declaration: the following predicates will
% be available at run-time.

:- export(push/1).
:- export(pop/1).
:- export(top/1).
:- export(is_empty/0).

% Code 

push(Item) :-
        nonvar(Item), 
        asserta_fact(storage(Item)).

pop(Item) :-
        var(Item),
        retract_fact(storage(Item)).

top(Top) :-
        storage(Top),
        !.

is_empty :-
        storage(_),
        !,
        fail.

is_empty.

:- comment(version_maintenance,off).

If we load this code at the Ciao toplevel shell:

        ?- use_package(objects).

        yes
        ?- use_class(library('class/examples/stack')).

        yes
        ?-

we can create two stack instances :

        ?- St1 new stack,St2 new stack.

        St1 = stack('9254074093385163'),
        St2 = stack('9254074091') ? ,

and then, we can operate on them separately:

        1 ?- St1:push(8),St2:push(9).

        St1 = stack('9254074093385163'),
        St2 = stack('9254074091') ? 

        yes
        1 ?- St1:top(I),St2:top(K).

        I = 8,
        K = 9,
        St1 = stack('9254074093385163'),
        St2 = stack('9254074091') ? 

        yes
        1 ?-

The interesting point is that there are two stacks. If the previous example had been a normal module, we would have a stack , but only one stack.

The next example introduces the concepts of inheritable predicate, constructor, destructor and virtual method. Refer to the following sections for further explanation.

%%----------------------------------%%
%% A generic class to perform       %%
%% item storage.                    %%
%%----------------------------------%%
:- class(generic).

% Public interface declaration:
:- export([set/1,get/1,callme/0]).

% An attribute
:- data datum/1.

% inheritable/1 is used for datum/1
% to become available to descendant
% classes (if any).
:- inheritable(datum/1).

% Attribute initialization. Attributes
% are easily initialized by writing clauses
% for them.

datum(none).

% Code

set(X) :-
        type_check(X),
        set_fact(datum(X)).

get(X) :-
        datum(X).

:- virtual type_check/1.

type_check(X) :-
        nonvar(X).

callme :-
        a_virtual(IMPL),
        display(IMPL),
        display(' implementation of a_virtual/0 '),
        nl.

% virtual/1 will tell the compiler to use the most
% descendant implementation of a_virtual/1 when calling
% it from inside this code (for example,see callme/0).
% If there is no descendant implementation for it, 
% the one defined bellow will be used.

:- virtual a_virtual/1.
a_virtual(generic).

% Constructor: in this case, every time an instance
% of this class is created, it will display a message.

generic :-
        display(' generic class constructor '),
        nl.

% Destructor: analogous to the previous constructor,
% it will display a message every time an instance
% of this class is eliminated.

destructor :-
        display(' generic class destructor '),
        nl.

And the following example, is an extension of previous class. This is performed by establishing an inheritance relationship:

%%----------------------------------%%
%% This class provides additional   %%
%% functionality to the generic     %%
%% class.                           %%
%%----------------------------------%%

:- class(specific).

% establish an inheritance relationship with "generic" class.
:- inherit_class(library('class/examples/generic')).

% override inherited datum/1.
% datum/1 is said to be overriden because there are both
% an inherited definition (from "generic" class) and a local one.

:- data datum/1. 
:- inheritable datum/1.

% Extend the public interface inherited from "generic".
% note that set/1 and a_virtual/0 has been also overriden. 
% undo/0 is a new added functionality.

:- export([set/1,undo/0]).

% Code

set(Value) :-
        inherited datum(OldValue),
        !,
        inherited set(Value),
        asserta_fact(datum(OldValue)).

set(Value) :-
        inherited set(Value).

undo :-
        retract_fact(datum(Last)),
        !,
        asserta_fact(inherited(datum(Last))).

undo :-
        retractall_fact(inherited(datum(_))).

% new implementation of a_virtual. This
% implementation will be used from inherited callme/0
% instead of that version defined at "generic".

a_virtual(specific).

% constructor

specific :-
        generic,
        retractall_fact(inherited(datum(_))),
        display(' specific class constructor '),
        nl.

% destructor

destructor :-
        display(' specific class destructor '),
        nl.

Additional examples may be found on the library/class/examples directory relative to your Ciao Prolog instalation.

Recommendations on when to use objects

We would like to give some advice in the use of object oriented programming, in conjunction with the declarative paradigm.

You should reconsider using O'Ciao in the following cases:

We recommend the usage of O'Ciao in the following cases:

Limitations on object usage

O'Ciao run-time speed is limited by the usage of meta-programming structures, for instance: X = (Object:mymethod(25)), call(X). O'Ciao will optimize static manipulation of objects (those that can be determined at compile time).


Go to the first, previous, next, last section, table of contents.