Author(s): Angel Fernandez Pineda.
Version: 1.11#222 (2004/5/24, 13:8:7 CEST)
Version of last change: 1.7#162 (2001/12/4, 16:2:58 CET)
O'Ciao classes are declared in the same way as traditional prolog modules. The general mechanism of source expansion will translate object-oriented declarations to normal prolog code. This is done transparently to the user.
Abstract
interfaces are restricted classes which declare exported predicates with no implementation. The implementation itselt will be provided by some class using an
implements/1
declaration. Only
export/1
and
data/1
declarations are allowed when declaring an interface. Normal classes may treated as interfaces just ignoring all exported predicate implementations.
class
)class
source expansion. To do so, source code must start with a module declaration which loads the class package:
:- class(ClassName).or a
module/3
declaration, as follows:
:- module(ClassName,[],[class]).interfaces are declared in a similar way:
:- interface(InterfaceName).Please, do not use SICStus-like module declaration, with a non-empty export list. In other case, some non-sense errors will be reported by normal Ciao module system. Most of the regular Ciao declarations may be used when defining a class, such as
concurrent/1
,
dynamic/1
,
discontiguous/1
,
multifile/1
, and so on.
However, there are some restrictions wich apply to those declarations:
It is a good practique to put all your declarations at the very begining of the file, just before the code itself.
export/1
,
public/1
,
inheritable/1
,
data/1
,
dynamic/1
,
concurrent/1
,
inherit_class/1
,
implements/1
,
virtual/1
.
class
)Declares a method or attribute to be part of the public interface.
The public interface is the set of predicates wich will be accesible from any code establishing an usage relationship with this class (see
use_class/1
for further information).
Publishing an attribute or method is very similar to exporting a predicate in a Prolog module.
Whether an inherited and exported predicate is overriden, it must be explicitly exported again.
An inherited (but not exported) predicate may become exported, without overriding it by the usage of this declaration.
Usage: :- export(Spec)
.
Spec
will be part of the public (exported) interface.
Spec
is a method or attribute specification.
(objects_rt:method_spec/1
)
Usage: :- public(Spec)
.
Declares a method or attribute to be inherited by descendant classes. Notice that all public predicates are inheritable by default. There is no need to mark them as inheritable.
Traditionaly, object oriented languages makes use of the protected concept. Inheritable/1 may be used as the same concept.
The set of inheritable predicates is called the inheritable interface.
Usage: :- inheritable(MethodSpec)
.
MethodSpec
is accessible to descendant classes.
MethodSpec
is a method or attribute specification.
(objects_rt:method_spec/1
)
Declares an attribute at current class. Attributes are used to build the internal state of instances. So, each instance will own a particular copy of those attribute definitions. In this way, one instance may have different state from another.
O'Ciao attributes are restricted to hold simple facts. It is not possible to hold a Head :- Body clause at an instance attribute.
Notice that attributes are multi-evaluated by nature, and may be manipulated by the habitual assert/retract family of predicates.
Attributes may also be initialized. In order to do so, simply put some clauses after the attribute definition. Each time an instance is created, its initial state will be built from those initialization clauses.
Note: whether a data/1 declaration appears inside an interface, it will be automatically exported.
Usage: :- data Spec
.
Spec
is an attribute.
Spec
is a method or attribute specification.
(objects_rt:method_spec/1
)
Usage: :- dynamic Spec
.
Declares a
concurrent attribute at current class. Concurrent attributes are just the same as normal attributes, those declared using
data/1
, except for they may freeze the calling thread instead of failing when no more choice points are remaining on the concurrent attribute.
In order to get more information about concurrent behavior take a look to the concurrent/1 built-in declaration on Ciao Prolog module system.
Usage: :- concurrent Spec
.
Spec
to be a concurrent attribute.
Spec
is a method or attribute specification.
(objects_rt:method_spec/1
)
Makes any public and/or inheritable predicate at inherited class to become accesible by any instance derived from current class.
Inherited class is also called the super class.
Only one inherit_class/1 declaration is allowed to be present at current source.
Notice that inheritance is public by default. Any public and/or inheritable declaration will remain the same to descendant classes. However, any inherited predicate may be overriden (redefined).
A predicate is said to be
overriden when it has been inherited from super class, but there are clauses (or a
data/1
declaration) present at current class for such a predicate.
Whether a public predicate is overriden, the local definition must also be exported, otherwise an error is reported.
Whether an inheritable predicate (not public) is overriden, the local definition must also be marked as inheritable or exported, otherwise an error is also reported.
Note: whether inherit_class/1 appears inside an interface, it will be used as an
implements/1
declaration.
Usage: :- inherit_class(Source)
.
Forces current source to provide an implementation for the given interface file. Such interface file may declare another class or a specific interface.
Every public predicate present at given interface file will be automatically declared as public at current source, so you must provide an implementation for such predicates.
The effect of this declaration is called interface inheritance,and there is no restriction on the number of implements/1 declarations present at current code.
Usage: :- implements(Interface)
.
Interface
.
Interface
is a valid path to a prolog file containing a class declaration or an interface declaration (without .pl extension).
(objects_rt:interface_source/1
)
This declaration may be used whenever descendant classes are to implement different versions of a given predicate.
virtual predicates give a chance to handle, in an uniform way, different implementations of the same functionality.
Whether a virtual predicate is declared as a method, there must be at least one clause of it present at current source. Whenever no special implementation is needed at current class, a never-fail/allways-fail clause may be defined (depending on your needs). For example:
:- virtual([ test1/1 , test2/2 ]). test1(_). test2(_,_) :- fail.
This kind of virtual methods are also known as abstract methods, since implementation is fully delegated to descendant classes.
An attribute may be also declared as a virtual one, but there is no need to write clauses for it.
Usage: :- virtual(VirtualMethodSpec)
.
VirtualMethodSpec
predicate in current source will use the most descendant implementation of it.
VirtualMethodSpec
is a method specification.
(objects_rt:virtual_method_spec/1
)
class
)This predicate qualificator may be used whenever you need to reference an attribute or method on the super class.
Since methods and attributes may be redefined, this qualificator is need to distinguish between a locally declared predicate and the inherited one, which has the same name.
There is no need to use inherited/1 if a particular inherited predicate has not been redefined at current class.
Usage: inherited(Goal)
Goal
at the super class
Goal
is a term which represents a goal, i.e., an atom or a structure.
(basic_props:callable/1
)
Determines which instance is currently executing self/1 goal.
Predicate will fail if argument is not a free variable. Otherwise, it will allways succeed, retrieving the instance identifier which is executing current code.
This functionality is very usefull since an object must have knowledge of other object's identifier in order to send messages to it.For example:
:- concurrent ack/0.
send_data_to_object(Data,Obj) :- self(X), Obj:take_this(Data,X), current_fact(ack).
acknowledge :- asserta_fact(ack).
take_this(Data,Sender) :- validate_data(Data), Sender:acknowledge.
Usage: self(Variable)
Variable
Variable
is a free variable.
(term_typing:var/1
)
Variable
is an unique term which identifies an object.
(objects_rt:instance_id/1
)
A constructor is a special case of method which complains the following conditions:
new/2
goal specified by the user.
This is a simple example of constructor declaration for the foo class:
foo :- display('an instance was born').
Constructor declaration is not mandatory, and there may be more than one constructor declarations (with different arity) at the source code.
This functionality is usefull when some computation is needed at instance creation. For example: opening a socket, clearing the screen, etc.
Whenever an inheritance relationship is established, and there is any constructor defined at the super class, you must call manually an inherited constructor. Here is an example:
:- class(foo). :- inherit_class(myclass). foo :- myclass(0), display('an instance was born'). foo(N) :- myclass(N).
Consequences may be unpredictable, if you forget to call an inherited constructor. You should also take care not to call an inherited constructor twice.
All defined constructors are inheritable by default. A constructor may also be declared as public (by the user), but it is not mandatory.
Usage:
A destructor is a special case of method which will be automatically called when instance destruction takes place.
A destructor will never be wanted to be part of the public interface, and there is no need to mark them as inheritable, since all inherited destructors are called by O'Ciao just before yours.
This is a simple example of destructor declaration:
destructor :- display('goodbye, cruel world!!!').
Destructor declaration is not mandatory. Failure or sucess of destructors will be ignored by O'Ciao, and they will be called only once.
This functionality is useful when some computation is need at instance destruction. For example: closing an open file.
Usage:
class
)
This describes the errors reported when declaring a class or an interface. The first section will explain compile-time errors, this is, any semantic error which may be determined at compile time. The second section will explain run-time errors, this is, any exception that may be raisen by the incorrect usage of O'Ciao. Some of those errors may be not reported at compile time, due to the use of meta-programational structures. For example:
functor(X,my_method,0),call(X).
O'Ciao is not able to check whether my_method/0 is a valid method or not. So, this kind of checking is left to run time.
:- meta_predicate example(addmodule).
example(X,FromModule) :- call(FromModule:X).
:- data attr.
:- dynamic attr(_).
:- data attr/m.
etc,etc...
attr(initial_value).
:- data attr/1.
It is a must to declare attributes before any clause of the given predicate.
:- multifile example/2.
Multifile predicates must be declared before any clause of the given predicate.
:- data my_attribute/1.
my_attribute(X) :- X>=0 , X<=2.
This is not allowed since attributes are assumed to hold simple facts. The correct usage for those initialization clauses is:
:- data my_attribute/1.
my_attribute(0).
my_attribute(1).
my_attribute(2).
:- public(p/1).
:- multifile(p/1).
This is not allowed since multifile predicates are not related to Object Oriented Programming.
data/1
declaration. You must declare at least one clause for every virtual method. Virtual attributes does not require any clause but a
data/1
declaration must be present.
implements/1
declaration present at your code where given Module is not declared as class nor interface.
implements/1
declaration.
public/1
declaration for F/A, but there is no definition for it at current class nor an inherited one.
self(abc)
.
asserta_fact(inherited(not_an_attribute(8)))
where not_an_attribute/1 was not declared as data or dynamic by the super-class (or corresponding ascendant).
:- meta_predicate attr(goal).
:- data attr/1.
There is no sense in declaring an attribute as meta-predicate.
:- class(myclass). :- inherit_class(other_class). myclass :- other_class.
O'Ciao works in conjunction with the Ciao Prolog module system, which also reports its own error messages. This will cause Ciao to report a little criptic error messages due to the general mechanism of source-to-source expansion. Those are some tips you must consider when compiling a class:
WARNING: (lns 28-30) [Item,Itema] - singleton variables in obj$remove/2
This error is relative to method remove/1.
set_prolog_flag/1
declaration will be usefull when declaring multiple constructors. It will avoid some awful warnings. Example:
:- class(myclass). %% Use this declaration whenever several constructors are needed. :- set_prolog_flag(multi_arity_warnings,off). myclass(_). myclass(_,_). :- set_prolog_flag(multi_arity_warnings,on).
class
)Go to the first, previous, next, last section, table of contents.