Difference between revisions of "Language Reference/Implementations"

From wiki.visual-prolog.com
m (spell & grammar)
m (spell & grammar)
Line 5: Line 5:
A class can privately (i.e. inside the implementation) declare and define more entities than those mentioned in the declaration. Especially, an implementation can declare fact databases that can be used to carry class and object state.
A class can privately (i.e. inside the implementation) declare and define more entities than those mentioned in the declaration. Especially, an implementation can declare fact databases that can be used to carry class and object state.


An implementation is a mixed scope, in the sense that it both contains the implementation of the class and of the objects produced by the class. The class part of a class is shared among all objects of the class, as opposed to the object part, which is individual for each object. Both the class part and the object part can contain facts and predicates, whereas domains, functors, and constants always belong to the class part, i.e. they do not belong to individual objects.
An implementation is a mixed scope, in the sense that it both contains the implementation of the class and of the objects produced by the class. The class part of a class is shared among all objects of the class, as opposed to the object part, which is individual for each object. Both the class part and the object part can contain facts and predicates, whereas domains, functors and constants always belong to the class part, i.e. they do not belong to individual objects.


By default all predicate and fact members declared in the implementation of a class are object members. To declare class members the section keyword (i.e. <vp>predicates</vp> and <vp>facts</vp>) must be prefixed with the keyword <vp>class</vp>. All members declared in such sections are class members.
By default all predicate and fact members declared in the implementation of a class are object members. To declare class members the section keyword (i.e. <vp>predicates</vp> and <vp>facts</vp>) must be prefixed with the keyword <vp>class</vp>. All members declared in such sections are class members.
Line 108: Line 108:
The associated class function is defined implicitly, i.e. there are no clauses for it anywhere.  
The associated class function is defined implicitly, i.e. there are no clauses for it anywhere.  


The class function allocates memory to hold the object, perform internal initialization of the object, and then invokes the object constructor on the created object. Finally, the constructed object is returned as the result of the constructor execution.
The class function allocates memory to hold the object, perform internal initialization of the object and then invokes the object constructor on the created object. Finally, the constructed object is returned as the result of the constructor execution.


So before the clauses of the constructor are invoked:
So before the clauses of the constructor are invoked:
Line 210: Line 210:
You also can declare "private" constructors in class implementations. This can be reasonable, for example, in the following situations:
You also can declare "private" constructors in class implementations. This can be reasonable, for example, in the following situations:


#When some predicate returns an object of ''construction type'', then in a class implementation can be declared, implemented, and called a "private" constructor to create such objects.
#When some predicate returns an object of ''construction type'', then in a class implementation can be declared, implemented and called a "private" constructor to create such objects.
#When some class declares several "public" constructors having a "same big part", then it can be reasonable to define in the class implementation a "private" constructor, which implements this "same big part". Then clauses of all these "public" constructors can simply call this "private" constructor to implement this "same big part".
#When some class declares several "public" constructors having a "same big part", then it can be reasonable to define in the class implementation a "private" constructor, which implements this "same big part". Then clauses of all these "public" constructors can simply call this "private" constructor to implement this "same big part".


Line 471: Line 471:
   Class2 = OOO:nameThis().</vip>
   Class2 = OOO:nameThis().</vip>


Class <vp>bbb</vp> inherits the definition of <vp>name</vp> and <vp>nameThis</vp> from <vp>aaa</vp>, but it re-implements <vp>className</vp>. In the goal we create a <vp>bbb</vp> object, and on this we call name and <vp>nameThis</vp>.
Class <vp>bbb</vp> inherits the definition of <vp>name</vp> and <vp>nameThis</vp> from <vp>aaa</vp>, but it re-implements <vp>className</vp>. In the goal we create a <vp>bbb</vp> object and on this we call name and <vp>nameThis</vp>.


The <vp>name</vp> predicate calls <vp>className</vp> directly, while <vp>nameThis</vp> calls <vp>This</vp>:<vp>className</vp>. The effects are different. The <vp>name</vp> predicate calls <vp>className</vp>, which is defined in <vp>aaa</vp>. But <vp>nameThis</vp> call the <vp>className</vp> that is defined on <vp>This</vp> and that is actually <vp>bbb::className</vp>, since <vp>This</vp> is a <vp>bbb</vp> object.
The <vp>name</vp> predicate calls <vp>className</vp> directly, while <vp>nameThis</vp> calls <vp>This</vp>:<vp>className</vp>. The effects are different. The <vp>name</vp> predicate calls <vp>className</vp>, which is defined in <vp>aaa</vp>. But <vp>nameThis</vp> call the <vp>className</vp> that is defined on <vp>This</vp> and that is actually <vp>bbb::className</vp>, since <vp>This</vp> is a <vp>bbb</vp> object.
Line 598: Line 598:
==== Predicate Rename Resolution ====
==== Predicate Rename Resolution ====


A predicate rename resolution states that the predicate is implemented as predicate with another name. The predicate must come from an inherited class and its type, mode, and flow must match exactly.
A predicate rename resolution states that the predicate is implemented as predicate with another name. The predicate must come from an inherited class and its type, mode and flow must match exactly.


<vipbnf><PredicateRenameResolution> :
<vipbnf><PredicateRenameResolution> :
Line 663: Line 663:
A finalizer is a procedure with no arguments and no return value, which has the name <vp>finalize</vp>. The predicate is implicitly declared and cannot be invoked directly from the program.
A finalizer is a procedure with no arguments and no return value, which has the name <vp>finalize</vp>. The predicate is implicitly declared and cannot be invoked directly from the program.


The main purpose of finalizers is to be able to release external resources, but there are no restrictions on what it can do. Finalizers should however be used with caution, recall that the time of their invocation is not completely known, and, therefore, it might also be difficult to predict the overall program state at the time where they are invoked.
The main purpose of finalizers is to be able to release external resources, but there are no restrictions on what it can do. Finalizers should however be used with caution, recall that the time of their invocation is not completely known and, therefore, it might also be difficult to predict the overall program state at the time where they are invoked.


Notice that there is no reason to retract object facts from an object in the finalizer, because this is automatically done in the finalization process.
Notice that there is no reason to retract object facts from an object in the finalizer, because this is automatically done in the finalization process.

Revision as of 14:03, 21 October 2008

A class implementation is used to provide the definitions of the predicates and constructors declared in the class declaration, as well as the definitions of any predicates supported by its constructed objects.

A class can privately (i.e. inside the implementation) declare and define more entities than those mentioned in the declaration. Especially, an implementation can declare fact databases that can be used to carry class and object state.

An implementation is a mixed scope, in the sense that it both contains the implementation of the class and of the objects produced by the class. The class part of a class is shared among all objects of the class, as opposed to the object part, which is individual for each object. Both the class part and the object part can contain facts and predicates, whereas domains, functors and constants always belong to the class part, i.e. they do not belong to individual objects.

By default all predicate and fact members declared in the implementation of a class are object members. To declare class members the section keyword (i.e. predicates and facts) must be prefixed with the keyword class. All members declared in such sections are class members.

Class members can reference the class part of a class, but not the object part.

Object members, on the other hand, can access both the class part and the object part of the class.

In the code in the implementation, the owner object is subsumed by all object predicates. The subsumed owner object can also be accessed directly through the special variable "This".

ClassImplementation :
   implement ClassName ScopeQualifications Sections end implement ClassName-opt

The ClassName in the end of the class implementation must (if present) be identical to the one in the beginning of the class implementation.

The ScopeQualifications must be of the kinds:

A supports qualification states the list of interfaces, which are supported privately by the class implementation.

A delegate qualification delegates functionality of (object) predicates from interfaces to predicates from objects, which can be stored as fact variables.

The Sections must be of the kinds:

constructorsSections are only legal if the class ClassName states a constructionType. Classes that states a ConstructionType are also object constructors, which constructs objects of the stated construction type.

Example

This example illustrates how class facts are shared among the objects of the class and how object facts are not shared.

Consider the interface aa and class aa_class:

interface aa
   predicates
       setClassFact : (integer Value).
       getClassFact : () -> integer.
       setObjectFact : (integer Value).
       getObjectFact : () -> integer.
end interface
class aa_class : aa
end class

The point of the predicates is that they store and fetches values from respectively class and object facts:

implement aa_class
   class facts
       classFact : integer := 0.
   facts
       objectFact : integer := 0.
   clauses
       setClassFact(Value) :- 
           classFact := Value.
       getClassFact() = classFact.
   clauses
       setObjectFact(Value) :- 
           objectFact := Value.
       getObjectFact() = objectFact.
end implement aa_class

Given this class consider the goal:

goal
   A1 = aa_class::new(),
   A2 = aa_class::new(),
   A1:setClassFact(1),
   A1:setObjectFact(2),
   ClassFact = A2:getClassFact(),
   ObjectFact = A2:getObjectFact().

The class fact is shared among all objects, so setting the class fact via A1 also affects the value obtained via A2. Hence, the value of ClassFact will be one, the value set via A1.

On the other hand, object facts belongs to each object. Therefore setting the object fact in A1 will not affect the value stored in A2. Hence value of ObjectFact is zero, the value that the fact was initialized to in A2.

Construction

This section describes object construction and, as such, it only deals with classes that produces objects.

Objects are constructed by calling a constructor.

Constructors are explicitly declared in constructors sections in class declarations and implementations. (see also Default Constructor).

A constructor actually has two associated predicates:

  • A class function, which returns a new constructed object.
  • An object predicate, which is used when initializing inherited objects.

The associated object predicate is used to perform initialization the object. This predicate can only be called from a constructor in the class itself and from a constructor in a class, which inherits from the class (i.e. base class initialization).

The associated class function is defined implicitly, i.e. there are no clauses for it anywhere.

The class function allocates memory to hold the object, perform internal initialization of the object and then invokes the object constructor on the created object. Finally, the constructed object is returned as the result of the constructor execution.

So before the clauses of the constructor are invoked:

  • All object facts variables that have an initialization expression are initialized.
  • All object facts that have clauses are initialized from these clauses.

This initialization is also performed on all (transitively) inherited sub-objects, before the clauses of the constructor are invoked.

The constructor clauses must:

  • Initialize all those single object facts and object fact variables that are not initialized before entrance.
  • Initialize all sub-objects.

The constructor clauses can do other things as well, but it must perform the initialization mentioned here to ensure that the object is valid after construction.

Note. During construction objects might not be valid and care must be taken not to access un-initialized parts of the object. (see Rules for Constructing Objects).

Default Constructor

A default constructor is a null-ary constructor with the name new/0. If a class that constructs objects does not declare any constructors in the class declaration, then the default constructor (i.e. new/0) is implicitly declared (in the class declaration). This means that each class has at least one constructor. So writing:

class aaa
end class aaa

is exactly the same as writing

class aaa
  constructors
     new : ().
end class aaa

It is legal to re-declare the default constructor explicitly.

It is not necessary to define (i.e. implement) the default constructor; if it is not defined then an effect-less definition is implicitly assumed. So writing

implement aaa
end implement aaa

is exactly the same as writing:

implement aaa
  clauses
     new().
end implement aaa

(Given that aaa has a default constructor).

Notice that a class has a default constructor if and only if:

  • it does not (publicly) declare any constructors at all;
  • or it declares new/0 as a constructor.

Which is the same (negated) as: A class does not have a default constructor if:

  • It publicly declares constructors;
  • and it does not publicly declare new/0 as a constructor.

Example

Given an interface aa, consider the following code:

class aa_class : aa
end class

The class aa_class declares no constructors; therefore, it implicitly declares the default constructor. Thus you can create an aa_class object like:

goal
   _A = aa_class::new(). % implicitly declared default constructor

Example

It is legal to implement the implicitly declared default constructor of aa_class:

implement aa_class
   clauses
       new() :-
          ...
end implement

Example

The bb_class class explicitly declares a constructor, which is not the default constructor; subsequently the class does not have the default constructor

class bb_class : aa
   constructors
       newFromFile : (file File).
end class

Example

The cc_class class declares the newFromFile/1 constructor, but it also declares the default new/0 constructor; so obviously, it has the default new/0 constructor

class cc_class : aa
   constructors
       new : ().                                          % default constructor
       newFromFile : (file File).
end class

Private Constructors

You also can declare "private" constructors in class implementations. This can be reasonable, for example, in the following situations:

  1. When some predicate returns an object of construction type, then in a class implementation can be declared, implemented and called a "private" constructor to create such objects.
  2. When some class declares several "public" constructors having a "same big part", then it can be reasonable to define in the class implementation a "private" constructor, which implements this "same big part". Then clauses of all these "public" constructors can simply call this "private" constructor to implement this "same big part".

Notice that if a class, which can construct objects, does not declare any constructors in the class declaration, then the default constructor (i.e. new/0) will be declared implicitly independently of whether the class implementation declares or not "private" constructors. That is, it is possible to write:

interface aa
end interface
class aa : aa
end class
implement aa
    constructors
           myCreate : ().
    clauses
            myCreate() :-
                  ...
end implement
% program code
   ...
   Obj = aa::new(),      % This is the declared IMPLICITLY default class constructor
   ...

Sub-object Construction

All constructors are responsible for initializing constructed objects to valid states. In order to obtain such a valid state all sub-objects (i.e. inherited classes) must be initialized as well.

The sub-objects can be initialized in one of two ways, either the programmer calls a constructor of the inherited class or the default constructor is automatically invoked. The latter requires that the inherited class actually has the default constructor, but this is no difference whether this default constructor is declared explicitly or implicitly - it will be called in both cases!

If the inherited class does not have a default constructor, then another constructor must be invoked explicitly. The default invocation of constructors of inherited classes takes place immediately after initialization of fact variables and facts with clauses and before entrance to the clauses of the constructor.

Constructors of inherited classes are invoked by the versions that does not return a value. If you call the version that returns a value then you are actually creating a new object, rather than invoking the constructor on "This" (see the example below).

Example

This implementation of the class bb_class inherits from the class aa_class and the default constructor of bb_class call a constructor of aa_class with a newly created cc_class object

implement bb_class inherits aa_class
   clauses
       new() :-
           C = cc_class::new(),                   % create a cc_class object
           aa_class::newC(C).                    % invoke constructor on inherited sub-object
      ...
end implement

Example 2

If a base class is not explicitly constructed, then it is implicitly constructed using the default constructor. So writing:

implement bbb
   inherits aaa
clauses
   myNew() :-
       doSomething().
end implement bbb

is exactly the same as writing:

implement bbb
   inherits aaa
clauses
   myNew() :-
       aaa::new(),
       doSomething().
end implement bbb

If aaa does not have a default constructor then this will, of course, give an error.

Notice that this rule (of course) can be combined with the rule discussed in the first paragraph of Default Constructor. So writing:

implement bbb
   inherits aaa
end implement bbb

Is exactly the same as writing (according to the rule discussed in the first paragraph of Default Constructor):

implement bbb
   inherits aaa
clauses
   new().
end implement bbb

Which is exactly the same as writing (the rule discussed above):

implement bbb
   inherits aaa
clauses
   new() :-
       aaa::new().
end implement bbb

Single (Object) Fact Initialization

Just like all constructors have to initialize/construct sub-objects, they also have to initialize all single facts of an object, before they are referenced the first time.

Notice that single class facts can only be initialized with clauses, since they are not related to an object. A class fact can be accessed before the first object is created.

Example

This example shows (1) how to initialize a fact variable by means of an expression; (2) how to initialize a single fact (point) by means of a clause; (3) how to initialize a single fact in the constructor and (4) where the default constructor of an inherited class is invoked:

implement bb_class inherits aa_class
   facts
       counter : integer := 0.
       point : (integer X, integer Y) single.
       c : (cc C) single.
   clauses
       point(0, 1).
       % The object is created and counter and point are initialized before entrance,
       % the default constructor aa_class::new/0 is also invoked before entrance
       new() :-
           C = cc_class::new(),
           assert(c(C)).
      ...
end implement

Construction by Delegation

As an alternative to construct the object directly in a constructor the job can be delegated to another constructor of the same class. This is done simply by invoking the other constructor (i.e. the version that does not return a value). When delegating construction we have to be sure that the object is actually constructed and that it is not "over-constructed". Single facts can be assigned a value as many times as one likes so they cannot be "over-constructed". Inherited classes, on the other hand, may only be initialized once during object construction.

Example

This example shows a typical use of construction by means of delegation. A constructor (new/0) invokes another constructor (newFromC/1) with a default value.

implement aa_class
   facts
       c : (cc C) single.
   clauses
       new() :-
           C = cc_class::new(),
           newFromC(C).
       newFromC(C) :-
           assert(c(C)).
      ...
end implement

Rules for Constructing Objects

The programmer must ensure that:

  • All sub-objects are initialized/constructed exactly once each.
  • All single facts are initialized (at least once).
  • That no sub-object is referenced before it is initialized/constructed.
  • That no single fact is used before it is initialized.

There is no guarantee about how clever the compiler is in detecting such problems at compile time.

The compiler may offer to generate runtime validation, it may also offer to non-safely omit such runtime validations.

"This"

An object predicate is always invoked on an object. This object carries the object facts and is subsumed by the implementation of object predicates. The object predicate has access to this implicit object. We shall call the object "This". There are two kinds of access to "This" implicit and explicit.

Explicit "This"

In every clause of every object predicate the variable This is implicitly defined and bound to "This", i.e. the object whose member predicate is executing.

Implicit "This"

In the clause of an object member predicate other object member predicates can be called directly, because "This" is implicitly assumed for the operation. Members of super-classes can also be invoked directly, as long as it is unambiguous which method is called (see Scoping & Visibility). Likewise the object facts (which are stored in "This") can be accessed.

"This" and Inheritance

[Notice this particular section is subject to change, as it is decided to change the language semantics in this matter.]

"This" always refer to an object belonging to the class in which "This" is used, also if that class is inherited by another class.

Assume the interface aa declared as follows:

interface aa
   predicates
       action : ().
       doAction : ().
end interface

also assume the class aa_class declared as follows:

class aa_class : aa
end class

And implemented as follows:

implement aa_class
   clauses
       action() :-
           doAction(),
           This:doAction().
       doAction() :-
           write("aa_class::doAction"), nl.
end implement

The following goal:

goal
   A = aa_class::new(),
   A:action().

Will write:

aa_class::doAction
aa_class::doAction

Now also consider class bb_class declared as follows:

class bb_class : aa
end class

And implemented as follows

implement bb_class inherits aa_class
   clauses
       doAction() :-
           write("bb_class::doAction"), nl.
end implement

The following goal:

goal
   B = bb_class::new(),
   B:action().

Will also write:

aa_class::doAction
aa_class::doAction

because (both implicit and explicit) "This" in aa_class refers to the object of class aa_class.

Now consider else one example:

interface iName
   predicates
       className : () -> string Class.
       name: () -> string Class.
       nameThis: () -> string Class.
end interface iName
 
class aaa : iName
end class aaa
 
implement aaa
   clauses
       className() = "aaa".
   clauses
       name() = className().
   clauses
       nameThis() = This:className().
end implement aaa
 
class bbb : iName
end class bbb
 
implement bbb
   inherits aaa
   clauses
       className() = "bbb".
end implement bbb
 
goal
   OOO = bbb::new(),
   Class1 = OOO:name(),
   Class2 = OOO:nameThis().

Class bbb inherits the definition of name and nameThis from aaa, but it re-implements className. In the goal we create a bbb object and on this we call name and nameThis.

The name predicate calls className directly, while nameThis calls This:className. The effects are different. The name predicate calls className, which is defined in aaa. But nameThis call the className that is defined on This and that is actually bbb::className, since This is a bbb object.

All in all Class1 is bound to the value "aaa", whereas Class2 is bound to "bbb".

Calling from a parent class to a child class like in nameThis is very often used to implement general functionality in a shared parent class. The general functionality relies on the refinements of the child classes for the non-generalized functionality.

Also consider this class:

interface iTest
   predicates
       test : () -> string Name.
end interface iTest
 
class ccc : iTest
end class ccc
 
implement ccc
   inherits aaa
   clauses
       test() = aaa::nameThis().
end implement ccc

ccc also inherits from aaa. Since ccc inherits from aaa it also implicitly supports the iName interface (i.e. privately). So when aaa calls This:className it call the one that ccc provides, which happens to be the one inherited from aaa.

Also consider this example:

class ddd : name
end class ddd
 
implement ddd
   inherits bbb
   clauses
       className() = "ddd".
end implement ddd
goal
   OOO = ddd::new(),
   Class1 = OOO:name(),
   Class2 = OOO:nameThis().

ddd inherits from bbb which we know inherits from aaa. When calling nameThis we actually call aaa::nameThis, which calls This:className. In this case This is the ddd object and therefore the effective call will go to ddd::className.

All in all a call to This:className goes to last child that supports an interface containing className.

Inherits Qualification

Inherits qualifications are used to state that an implementation inherits from one or more classes. Inheritance has only influence on the object part of a class.

The purpose of inheriting from other classes is to inherit behavior from these classes.

When a class cc inherits from a class aa, this means that the implementation of the cc class automatically implicitly (privately) supports the construction type (interface) of the aa class. (If the class aa implementation already support the cc construction type explicitly then there is of course no difference.)

Therefore, notice that the same predicate, for example p, cannot be declared in the construction type interface of a cc class and in the construction type interface of an inherited aa class. (The compiler will detect this and generates an error that a predicate is declared in 2 places.) Let us discuss this in some details. Let us suppose that a cc class has a construction type interface cci and some other aa class has a construction type interface aai. Let both aai and cci interfaces declare the same predicate p. Till the aa and cc classes are independent, the compiler does not detect any problems. But as soon as we declare that the cc class inherits from the aa class, then cc class starts to support also the aai interfaces. Therefore, the cc class starts to see both declarations of the predicate p, which will be reported as a compiling time error. The only possibility to avoid such ambiguity in the predicate p declaration is using of the Predicates from Interface section in the cci interface declaration. For example like:

interface cci
 predicates from aai
    p(), ...
end interface cci

Object predicates can be inherited: If the class does not implement a certain of its object predicates, but one of the classes it inherits from does implement this predicate, then that predicate will be used for the current class.

The class that inherits from another class does not have any special privileges towards the inherited class: It can only access the embedded object through its construction type interface.

Inheritance must be unambiguous. If the class defines the predicate itself then there is no ambiguity, because then it is this predicate definition that is exposed. If only one inherited class supports the predicate then it is also unambiguous. But if two or more classes supports the predicate then it is ambiguous which class provides the definition. In that case the ambiguity must be resolved by means of a resolve qualification (see Resolve Qualification).

Object predicates from inherited classes can be called directly from object predicates in the current class, since the embedded sub-object is implicitly used as predicate owner. Class qualification can be used to resolve calling ambiguities for object predicates from inherited classes.

InheritsQualification :
   inherits ClassName-comma-sep-list

Resolve Qualification

As mentioned elsewhere all ambiguities related to calling predicates can be avoided by using qualified names.

But when it comes to inheritance this is not the case. Consider the following example:

interface aa
   predicates
       p : () procedure ().
       ...
end interface
class bb_class : aa
end class
class cc_class : aa
end class
class dd_class : aa
end class
implement dd_class inherits bb_class, cc_class
end implement

In this case it is ambiguous which of the classes bb_class and cc_class that would provide the implementation of aa for dd_class. (Notice that when we say that a class implements an interface, it means that it provide definitions for the predicates declared in the interface.)

It would of course be possible to add clauses to the implementation of dd_class, which would effectively solve the job. Consider, for example, the following clause, which would "export" the predicate p from bb_class:

clauses
   p() :- bb_class::p().

But, with this code we have not really inherited the behavior from bb, we have actually delegated the job to the bb_class part of our class.

So to resolve this kind of ambiguities (and use real inheritance rather than delegation) we use a resolve section. A resolve section contains a number of resolutions:

ResolveQualification :
   resolve Resolution-comma-sep-list
Resolution :
   InterfaceResolution
   PredicateFromClassResolution
   PredicateRenameResolution
   PpredicateExternallyResolution

A resolve qualification is used to resolve an implementation from the specified source.

Predicate Resolution

PredicateFromClassResolution :
   PredicateNameWithArity from ClassName

A predicate from class resolution states that the predicate is implemented by the specified class.

To resolve a predicate to a class:

  • the class must implement the predicate to be resolved, this implies that the predicate must origin in the same interface as the one that should be inherited
  • the class must be mentioned in the inherits section

Predicate Rename Resolution

A predicate rename resolution states that the predicate is implemented as predicate with another name. The predicate must come from an inherited class and its type, mode and flow must match exactly.

PredicateRenameResolution :
   PredicateNameWithArity from ClassName :: PredicateName

Interface Resolution

An interface resolution is used to resolve a complete interface from one of the inherited classes. Thus an interface resolution is a short way of stating that all the predicates in the interface should be resolved from the same class.

InterfaceResolution :
   interface InterfaceName from ClassName

The class must publicly support the resolved interface.

If both a predicate resolution and an interface resolution cover some predicate name, then the predicate resolution is used. I.e. the specific resolution overrides the less specific ones.

It is valid for a predicate to be covered by several interface resolutions, as long as these all resolve the predicate to the same class. If on the other hand a predicate is resolved to different classes by interface resolutions, then the resulting ambiguity must be resolved by a predicate resolution.

Note: The syntax of resolutions is not capable of resolving different overloading of a predicate to different classes.

Example

We can solve the ambiguity from the example above by providing an interface resolution. In this case we have chosen to inherit the implementation of aa_class from cc_class, except that we will inherit p from bb_class

implement dd_class
   inherits bb_class, cc_class
   resolve
       interface aa from cc_class
       p from bb_class
end implement

External Resolution

A predicate externally resolution states that the predicate is not at all implemented in the class itself, but in an external library. External resolutions can only be used for class predicates. I.e. object predicates cannot be resolved externally.

It is important that the calling convention, link name and argument types correspond to the implementation in the library.

Both private and public predicates can be resolved externally.

PredicateExternallyResolution : PredicateNameWithArity externally

Dynamic External Resolution

A predicate externally resolution also provide syntax for dynamic loading of private and public class predicates from DLLs.

The syntax is:

PredicateExternallyResolutionFromDLL :
  PredicateNameWithArity externally from DllNameWithPath
DllNameWithPath :
   StringLiteral

If the predicate predicateNameWithArity is missed in the DLL DllNameWithPath, then the dynamic loading provides the possibility to run a program until it actually invokes the missed predicate. The runtime error will occur on such invocation. The DllNameWithPath is the path to the DLL on the machine where the program should run. One can absolute or relative. For example if the required dll is situated in the one level up from directory which the application loaded, then the DllNameWithPath should be like "../DllName". See also Dynamic Library Search Order in MSDN.


Finalization

Once an object cannot be reached by the program it can be finalized, the semantics of the language does not say exactly when the object will be finalized. The only thing that is guaranteed is that it is not finalized as long as it can be reached from the program. In practice the object is finalized, when it is wasted by the garbage collector. Finalization is the opposite of construction and will remove the object from memory.

Classes can also implement a finalizer, which is a predicate that is invoked when the object is finalized (before it is removed from memory).

A finalizer is a procedure with no arguments and no return value, which has the name finalize. The predicate is implicitly declared and cannot be invoked directly from the program.

The main purpose of finalizers is to be able to release external resources, but there are no restrictions on what it can do. Finalizers should however be used with caution, recall that the time of their invocation is not completely known and, therefore, it might also be difficult to predict the overall program state at the time where they are invoked.

Notice that there is no reason to retract object facts from an object in the finalizer, because this is automatically done in the finalization process.

All objects are finalized before the program can terminate (unless an abnormal situation like power failure prevents this).

Example

This example uses a finalizer to ensure that a database connection is closed properly.

implement aa_class
   facts
       connection : databaseConnection.
   clauses
       finalize() :-
           connection:close().
   ...
end implement aa_class

Delegate Qualification

A delegate section contains a number of delegations:

DelegateQualification :
   delegate Delegation-comma-sep-list
Delegation :
   PredicateDelegation
   InterfaceDelegation

The delegate qualifications are used to delegate implementations of object predicates to the specified source.

There are two kinds of the delegate qualifications. The Predicate Delegation and the Interface Delegation. The Interface Delegation is used to delegate implementations of a complete set of object predicates declared in an interface to an implementation of another object, stored as fact variable. Thus an interface delegation is a short way of stating that implementations of all predicates in the interface should be delegated to an implementation of the object, stored in fact variable.

The delegate sections look like a correspondent (predicate/interface) resolve sections, except that you delegate to fact variables keeping constructed objects of classes, rather than to inherited classes.

Predicate Delegation

A object predicate delegation states that the predicate functionality is delegated to the predicate in the object specified with the fact variable FactVariable_of_InterfaceType.

PredicateDelegation :
   PredicateNameWithArity to FactVariable_of_InterfaceType

To delegate a predicate to an object passed with the fact variable:

  • The fact variable FactVariable_of_InterfaceType must have a type of an interface (or of its sub-type), which declares the predicate predicateNameWithArity.
  • The object supporting the interface must be constructed and be assigned to the fact variable FactVariable_of_InterfaceType.

Consider the following example:

interface a
   predicates
       p1 : () procedure ().
       p2 : () procedure (). 
end interface
 
interface aa
   supports a
end interface
 
class bb_class : a
end class
 
class cc_class : a
end class
 
class dd_class : aa
  constructors
     new : (a First, a Second).
end class
 
implement dd_class
    delegate p1/0 to fv1, p2/0 to fv2
    facts
       fv1 : a.
       fv2 : a.
   clauses
       new(I,J):-
           fv1 := I,
           fv2 := J.
end implement

Later it will be possible to construct objects of the type a and assign them to fact variables fv1 and fv2 to define to objects of which class we really delegate definitions of p1 and p2 functionality. Consider, for example,

goal
   O_bb = bb_class::new(),
   O_cc = cc_class::new(),
   O_dd = dd_class::new(O_bb, O_cc),
   O_dd : p1(),                                   % This p1 from O_bb object
   O_dd : p2().                                   % This p2 from O_cc object

Actually in Visual Prolog delegation has the same effect as if you add clauses to the implementation of dd_class that explicitly specify, from object of which class the predicate functionality is "exported". That is for example, as if the following clause is determined in the implementation of dd_class:

clauses
   p1() :- fv1:p1().

Interface Delegation

When you need to specify that functionality of all predicates declared in an interface InterfaceName are delegated to predicates from objects of the same inherited class, you can use the Interface Delegation specification:

InterfaceDelegation :
   interface InterfaceName to FactVariable_of_InterfaceType

Thus an interface delegation is a short way of stating that functionality of all predicates declared in the interface InterfaceName should be delegated to objects stored as the fact variable FactVariable_of_InterfaceType. Objects should be assigned to the fact variable FactVariable_of_InterfaceType, which should be of the InterfaceName type (or its sub-type).

To delegate an interface to an object passed with the fact variable:

  • The fact variable FactVariable_of_InterfaceType must have a type of an interface InterfaceName or of its sub-type.
  • The object supporting the interface must be constructed and be assigned to the fact variable FactVariable_of_InterfaceType.

The predicate delegation has higher priority than the interface delegation. If to a predicate both delegations are specified. That is, the predicate delegation is specified to the predicate and it is declared in an interface, which has the interface delegation. Then the higher priority predicate delegation will be implemented.