Vous êtes sur la page 1sur 147

Visual Prolog 7.

3
Language Reference
(c) 2010 Prolog Development Center A/S http://www.visual-prolog.com

Visual Prolog 7.3 Language Reference


This document describes the syntax and semantics of the Visual Prolog programming language. Visual Prolog is a strongly typed object oriented programming language based on the logical programming language Prolog. A Visual Prolog program consists of a goal and a number of:
n n n

Interfaces Class declarations and Class implementations

Which contain declarations and definitions of Prolog entities:


n n n n n

Domains Constants Predicates Properties Fact databases

The "actual" code of a Visual Prolog is the clauses, which are located in class implementations and which implements predicates.

Visual Prolog 7.3 Language Reference

Page 2 / 147

Basic Concepts
Types and Subtypes
Types Visual Prolog types are divided into object types and value types. Objects have mutable state, whereas values are immutable. Object types are defined by interface definitions. The value types include numerical types, strings, character types and compound domains. Compound domains are also known as algebraic data types. Simpler forms of compound domains are structure and enumeration types, whereas more complex forms represents tree structures. Subtypes Types are organized in a subtype hierarchy. Subtypes are used to introduce subsumptionpolymorphism: Any context that expects a value of some type will equally well accept a value of any subtype. Or if we turn it around, we can say, that values of a certain type are automatically converted to any super-type where needed and can thus be used as having the super-type without explicit type conversion. Subtypes can be derived from any value type, except from algebraic data types. Types derived from algebraic data types are synonym types rather than subtypes, i.e. they are the same type rather than a subtype. The notion of subtypes relates closely to the notion of subsets. But it is important to notice that even though a type is "mathematically" a subset of another type it need not be a subtype. A type is only subtype of another type if it is declared to be so. domains t1 = [1..17]. t2 = [5..13]. t3 = t1 [5..13]. t1 is an integral type whose values are the integers from 1 to 17 (both inclusive). Likewise, t2 contains the values from 5 to 13. So t2 is a subset of t1, but t2 is not a subtype of t1. On the other hand, t3 (which contains the same values as t2) is a subtype of t1, because it is declared to be so. The language contains a few implicit subtype relations, but otherwise subtype relations are explicitly stated in type definitions. Object types are organized in a subtype hierarchy rooted in the predefined object type object, i.e. any object type is a subtype of object. Object subtypes are defined by means of stating that one interface supports another. If an object has an interface/object type that supports a certain other interface, then the object also has that type and can without further interference be used as such an object. See also: Universal and Root Types

Object System
External View The description in this section is not supposed to be an introduction to classes; it is intended as a clarification of the class notions in Visual Prolog. The reader is expected to be familiar with common
Visual Prolog 7.3 Language Reference Page 3 / 147

class notions. The description is purely conceptual in the sense that it does not refer to any syntax, implementation, etc. Moreover, this description does not consider any operational or programmatic aspects. While the reasons for introducing classes, objects, etc are mostly of programmatic nature, we find it valuable to describe the underlying concepts without reference to these programmatic reasons. The class concept of Visual Prolog is based on the following three semantic entities:
n n n

objects interfaces classes

Object An object is set of named object member predicates and a set of supported interfaces. Objects actually also have a state, but this state can only be changed and observed through the member predicates. We say that the state is encapsulated in the object. Here encapsulation means the ability of an object to hide its internal data and methods, making only the intended parts of the object programmatically accessible. The importance of encapsulation and modularity is well known. Encapsulation helps building more structured and readable programs, because objects are treated like black boxes. Look at a complex problem, find a part, which you can declare and describe. Encapsulate it into an object, construct an interface and continue so, until you have declared all the sub-problems. When you have encapsulated the objects of the problem, and ensured, that they work correctly, you can abstract from them. Interface An interface is an object type. It has a name and defines a set of named object predicates. Interfaces are structured in a supports hierarchy (the structure is a semi-lattice rooted in the interface object). If an object has a type denoted by an interface, then it also has the type of any supported interfaces. Therefore, the supports hierarchy is also a type hierarchy. An interface is a subtype of all its supported interfaces. We also say that the object supports the interface. If the interface is named X, then we say that the object is an X, or an X object. Class A class is a named object factory; it can create objects corresponding to a certain interface. Any object is created by a class, if an object was created by the class, which uses the interface C to construct objects then we call it a "C object". All objects that are constructed by a certain class share the same definition of the object member predicates, but each object has its own state. Thus, the object member predicates is actually part of the class, whereas the state of the object is part of the object itself. A class also contains another set of named predicates and an encapsulated state, known as the class members and class state, respectively. The class members and the class state exist on a per class basis, whereas the object members and object state exist on a per object basis. The class state can be accessed both by class members and by object members. Notice! The set of object member predicates that a class defines is the union of the predicates declared (transitively) in the interfaces of that class. More specifically this means that, if the same predicate is declared in two different interfaces then the class will only provide one definition of that predicate. So the class only sounds if that makes sense, i.e. if the intended semantics of these two inherited predicates are the same. Notice that interface support must be specified explicitly. The fact that some class provides the predicates corresponding to some interface does not imply that the class supports the interface.

Visual Prolog 7.3 Language Reference

Page 4 / 147

Module In fact a class need not be able to manufacture objects at all. Such class may have only class members and the class state. And therefore, such class can be considered to be a module rather than a class. Identity Every object is unique: objects have a changeable state and since the state of the objects can be observed by means of their member predicates an object is only identical to itself. I.e. even if the states of two objects are identical, the objects are not identical, because we can change the state of one object without changing the state of the other object. We never have direct access to an object state, we always access an object state by means of a reference to the object and while an object is only identical to itself, we can have many references to the same object. Thus, the same object can be accessed through many different references. Classes and interfaces are also unique; they are identified by their names. Two interfaces or classes cannot have the same name in the same program. A class and an interface can only have the same name if the class constructs objects of that interface. The essence is that structural equality does not imply identity for objects, classes nor interfaces. Internal View Where the previous section described objects, classes, and interfaces in terms of their external behavior, this section will extend this description with internal issues. These internal issues have more programmatically nature; they are concerned with splitting of classes onto the declaration part and the implementation part. From a programmatic point of view, classes are the central item: the code is contained in the classes. Interfaces mainly have static importance. In fact, interfaces only exist in the textual representation of a program; there is no (direct) runtime representation of an interface. Objects, on the other hand, have mainly dynamic importance. Objects are not directly visible in the program; they do not exist until the program actually runs. A class consists of a declaration and an implementation. The declaration declares the public accessible parts of the class and the objects it generates. The implementation on the other hand defines the entities declared in the class declaration. The basic implementation of predicates is of course clauses, but predicates can also be defined by means of inheritance, or resolved to external libraries. A class declaration in Visual Prolog is purely declarative. It only states which entities you can access: not how or where they are implemented. A class implementation can declare and define further entities (i.e. domains, predicates, etc), which are only visible inside the class itself. I.e. they are private. The state of an object is stored in the object as its facts. These facts are declared as normal facts (database) sections in the implementation of the class. Facts are local to each object (like other object entities), whereas class facts are shared among all objects of the class. Facts can only be declared in the implementation of a class and, therefore, cannot be accessed (directly) from outside the class. The implementation of a class can also declare that it supports more interfaces than mentioned in the declaration. This information is, however, only visible in the implementation itself and is, therefore,

Visual Prolog 7.3 Language Reference

Page 5 / 147

private. Code Inheritance In Visual Prolog code inheritance only takes place in the implementation of a class. Visual Prolog has multiple inheritance. You inherit from a class by mentioning the class in a special inherits section of the implementation. The classes you inherit from are called parent classes or super-classes. Childclass or sub-class is the dual to parent class, we also say that the child classes inherit from the parent classes. A child class can only access its parent classes through its public interface, i.e. it does not receive any extra privileges than anybody else that use the parent class.

Scoping & Visibility


Name Categories All names (identifiers) in Visual Prolog are syntactically divided into two major groups:
n n

Constant names (starting with a lowercase letter) Variable names (starting with an uppercase letter or an underscore)

Constant names (identifiers) are divided into the following categories:


n n n

n n

Type names (i.e. domains and interfaces). Domain carriers (i.e. classes and interfaces). Names without parentheses (i.e. constants, fact variables of non-function type and nullaryfunctors). Value returning names of arity N (i.e. functions, functors and fact-variables of function type). Non-value-returning names of arity N (i.e. predicates, facts and fact variables of predicate type).

Visual Prolog demands that names do not conflict at the point of declaration, because then it would be impossible to solve the conflict at point of usage. Declarations can only conflict if they are in the same scope, because qualification with scope can be used to solve the conflict. A name in one category can never be in conflict with a name in another category, but as we shall see a single declaration might place a name in several categories. Packages The basic units of code organization accepted in Visual Prolog are packages. We use packages in Visual Prolog to organize and structuring things. The use of packages ensures homogeneity in structuring principles among different projects. Packages define the standard for tool structuring and ease sharing source code among projects. The package is a collection of several grouped together interfaces and classes. The package provides some common name to all these interfaces and classes. Each declaration or implementation of each interface or class from a package is placed in a separate file. Each filename (of these files) coincides with the name of a class or an interface that is declared or implemented in this file. All package files are stored in the same separate package directory. (If a package contains sub-packages, then they are placed in subdirectories of the package directory.) The concept of packages is used for grouping together several linked interfaces and classes. Packages can play a role of some class library. Packages can be used in your program instead of direct placing all used interfaces and classes into your program. The accepted in Visual Prolog structure of packages and how packages should be included into projects are described in the VDE part of this help. (See Creating a Package in Creating New Project Items.) Visibility, Shadowing, and Qualification

Visual Prolog 7.3 Language Reference

Page 6 / 147

Most of the scoping rules are already mentioned above. This section will complete the picture. An interface definition, a class declaration and a class implementation are scopes (scopes cannot be nested). An implementation (privately) extends the scope of the corresponding class declaration. The visibility is the same everywhere in a scope. This does especially mean that no matter where in a scope something is declared, it is visible in the whole scope. Public names from supported interfaces and super-classes are directly (i.e. without qualification) available inside a scope, if it is unambiguous where they come from. It is illegal to use a name whose origin is ambiguous. All ambiguities in predicate calls can be removed by qualifying the predicate name with the class name (e.g. cc::p). This qualification is also used to qualify calls of object member predicates of super-classes on the current object. Visual Prolog has the following shadowing hierarchy:
n n

Local Super-class & opened scopes

Opened scopes have the same status as super-classes, so in the sequel we will just say superclasses. The hierarchy means that a local declaration will shadow a super-class declaration. But there is no shadowing between super-classes; all super-classes have equal preference. If two or more super classes contain conflicting declarations then these declarations can only be accessed by means of qualification. Example Assume the interface aa and the class aa_class: interface aa predicates p1 : () procedure (). p2 : () procedure (). p3 : () procedure (). end interface class aa_class : aa end class Also assume the class bb_class: class bb_class predicates p3 : () procedure (). p4 : () procedure (). end class bb_class In the context of these classes consider the implementation of a class cc_class

Visual Prolog 7.3 Language Reference

Page 7 / 147

implement cc_class inherits aa_class open bb_class predicates p2 : () procedure (). p5 : () procedure (). clauses new() :p1(), % aa_class::p1 p2(), % cc::p2 (shadows aa_class::p2) aa_class::p2(), % aa_class::p2 p3(), % Illegal ambiguous call: aa_class::p3 or bb_class::p3 aa_class::p3(), % aa_class::p3 bb_class::p3(), % bb_class::p3 p4(), % bb_class::p4 p5(), % cc::p5 end implement cc_class

Visual Prolog 7.3 Language Reference

Page 8 / 147

Lexical Elements
The Visual Prolog Compiler is applied to a source file. This source file may include other source files, which are (conceptually) inserted into the original source file to constitute one compilation unit. The compilation of a compilation unit is done in two conceptual steps:
n n

first the input is transformed into a sequence of tokens; and then these tokens are syntactically analyzed and transformed into executable code.

The lexical analysis of the program will break the compilation unit CompilationUnit into a list of input elements InputElement CompilationUnit: InputElement-list

InputElement: Comment WhiteSpace Token Only tokens are significant to the subsequent syntax analysis.

Comments
A Visual Prolog comment is written in one of the following ways:
n

The /* (slash, asterisk) characters, followed by any sequence of characters (including new lines), terminated by the */ (asterisk, slash) characters. These comments can be multi-lined. They can also be nested. The % (percent sign) character, followed by any sequence of characters. Comments that begin with character % (percent sign) continue until the end of the line. Therefore, they are commonly called single-line comments.

Notice the following comment example: /* Begin of Comment1 %NestedComment2*/ This mark does not close a multi-line comment because it is inside a single This is the real termination of Comment1 */

Whitespace
WhiteSpace: Space Tab NewLine Here Space is a space character, Tab is a tabulation character and NewLine is a new line character.

Tokens
Token: Identifier Keyword Punctuator Operator Literal
Visual Prolog 7.3 Language Reference Page 9 / 147

Identifiers Identifier: LowercaseIdentifier UppercaseIdentifier AnonymousIdentifier Ellipsis A LowercaseIdentifier is a sequence of letters, digits, and underscores that starts with a small letter. An UppercaseIdentifier is a sequence of letters, digits, and underscores that starts either with a capital letter or with an underscore. AnonymousIdentifier : _

Ellipsis : ... Keywords Keywords are divided into major and minor keywords, this division is only cosmetic however, there is no formal difference between major and minor keywords. In the sequel we will however use different coloring for them. Keyword : MajorKeyword MinorKeyword

MajorKeyword : one of class clauses constants constructors delegate domains end facts goal guards implement inherits interface monitor namespace open predicates properties resolve supports

Visual Prolog 7.3 Language Reference

Page 10 / 147

MinorKeyword : one of align and anyflow as bitsize catch determ digits div do else elseif erroneous externally failure finally foreach from if language mod multi nondeterm or procedure quot rem single then to try All keywords except as and language are reserved words. Notice that div and mod are also reserved words, but these are categorized as operators. guards and monitor are not used in the language, but are reserved for future usage. Punctuation Marks Punctuation marks in Visual Prolog have syntactic and semantic meaning to the compiler, but do not specify by themselves an operation that yields a value. Some punctuation marks, either alone or in combinations, can also be Visual Prolog operators. Punctuation marks are: PunctuationMarks: one of ! , . # [ ] Operators Operators specify an evaluation to be performed on involved operands. Operators: one of + / * ^ = div mod quot rem < > < > > < < = > = := All operators are binary, but - and + also exist as unary operators. div and mod are reserved words.

:-

::

Literals
Literals fall into following categories: integer, character, floating-point, string, binary and list. Literal: IntegerLiteral RealLiteral CharacterLiteral StringLiteral BinaryLiteral ListLiteral CompoundDomainLiteral

Visual Prolog 7.3 Language Reference

Page 11 / 147

Integral Literals IntegerLiteral: UnaryPlus-opt DecimalDigit-list UnaryMinus-opt DecimalDigit-list UnaryPlus-opt OctalPrefix OctalDigit-list UnaryMinus-opt OctalPrefix OctalDigit-list UnaryPlus-opt HexadecimalPrefix HexadecimalDigit-list UnaryMinus-opt HexadecimalPrefix HexadecimalDigit-list UnaryPlus: + UnaryMinus: OctalPrefix: 0o OctalDigit: one of 01234567 DecimalDigit: one of 0123456789 HexadecimalPrefix: 0x HexadecimalDigit: one of 0123456789AaBbCcDdEeFf An integral literal can belong to integer or unsigned domains and it should not exceed maximum and minimum integer or unsigned values. Real Literal RealLiteral: UnaryMinus-opt DecimalDigit-list FractionOfFloat-opt Exponent-opt FractionOfFloat: . DecimalDigit-list Exponent: ExponentSymbol ExponentSign-opt DecimalDigit-list ExponentSymbol: one of e E ExponentSign: one of - + A floating literal should not exceed maximum and minimum real values. Character Literals CharacterLiteral: ' CharacterValue ' CharacterValue can be any printable character or an escape sequence:
n n

\\ representing \ \t representing Tab character

Visual Prolog 7.3 Language Reference

Page 12 / 147

n n n n n

\n representing New Line character \r representing carriage return \' representing single quote \" representing double quote \uXXXX, here XXXX should be exactly four HexadecimalDigit's representing the Unicode character corresponding to the digits.

String Literals StringLiteral: StringLiteralPart-list

StringLiteralPart: @" AnyCharacter-list-opt " " CharacterValue-list-opt " A string literal consists of one or more StringLiteralPart's, which are concatenated. StringLiteralPart's starting with @ does not use escape sequences, except for the:
n

"" representing double quote.

Whereas StringLiteralPart's without @ uses the following escape sequences:


n n n n n n

\\ representing \ \t representing Tab character \n representing New Line character \r representing carriage return \" representing double quote \uXXXX, here XXXX should be exactly four HexadecimalDigit's representing the Unicode character corresponding to the digits.

Binary Literals BinaryLiteral: $[ ElementValue-comma-sep-list-opt ] ElementValue: IntegerLiteral ElementValue should be any integral arithmetic expression (for example, constant), which should be calculated while compilation-time and be in the range from till 255. List Literals All elements in a list literal must belong to the same domain (or to compatible domains). This domain can be any built-in or user defined domain, for example, it can be integral, character, binary, compound domain, etc. ListLiteral: [ SimpleLiteral-comma-sep-list-opt ] [ SimpleLiteral-comma-sep-list | ListLiteral ] Here SimpleLiteral can be:

Visual Prolog 7.3 Language Reference

Page 13 / 147

SimpleLiteral: IntegerLiteral RealLiteral CharacterLiteral StringLiteral BinaryLiteral ListLiteral CompoundDomainLiteral Example These are all valid list literals: [] [1,2,3] ["abc", "defg"] % empty list % list of integers % list of strings

Example This is invalid because the elements in a list must all have same type: [1,"abc"] % this is INVALID list

Compound Domain Literals Terms of user defined compound domains can be treated as literals if all their arguments are literals.

Visual Prolog 7.3 Language Reference

Page 14 / 147

Compilation Units
A program consists of a number of compilation units. The compiler compiles each of these compilation units separately. The result of a compilation is an object file. These object files (and perhaps other files) are linked together to produce the project target. A program must contain exactly one goalSection, which is the entry point to the program. A compilation unit has to be self-contained in the sense that all referenced names have to be either declared or defined in the unit. Interface definitions and class declarations can be included in several compilation units (the definitions/declarations must be identical in all units where they are included), whereas class implementations (definitions) may only be defined in a single unit. Every declared item must also be defined in the project, but some items can be defined in libraries, meaning that they do not need a textual definition. A compilation unit (which is perhaps composed by using #include directives) is a sequence of compilation items. CompilationUnit : CompilationItem-list-opt A compilation item is an interface, a class declaration, a class implementation, the goal section or it can be a conditional compilation item, which are described in Conditional Compilation. CompilationItem : Directive NamespaceEntrance ConditionalItem InterfaceDefinition ClassDeclaration ClassImplementation GoalSection See also
n n n n n n n

Interfaces Classes Implementations Namespace Entrances Goal Section Directives Conditional Item

Visual Prolog 7.3 Language Reference

Page 15 / 147

Interfaces
An interface definition defines a named object type. Interfaces can support other interfaces. See Supports Qualification for further details. All predicates declared in an interface are object members in objects of the interface type. An interface is also a global scope, in which constants and domains can be defined. Thus constants and domains defined in an interface are not part of the type that the interface denotes (or of objects having this type). Such domains and constants can be referenced from other scopes by qualification with the interface name: interface::constant, or by using an open qualification. (See Open Qualification.) InterfaceDeclaration : interface IinterfaceName ScopeQualifications Sections end interface IinterfaceName-opt

InterfaceName : LowerCaseIdentifier See also Generic Interfaces and Classes and Monitors. The InterfaceName in the end of the construction must (if present) be identical to the one in the beginning of the construction. The ScopeQualifications must be of the kinds:
n n

Supports Qualification Open Qualification

The Sections must be of the kinds:


n n n n n n

ConstantsSection DomainsSection PredicatesSection PredicatesFromInterface PropertiesSection ConditionalSection

All sections contained (transitively) in conditional sections must also be of those kinds.

The interface: object


If an interface does not explicitly support any interfaces, then it implicitly supports the build-in interface object. The object is an empty interface, i.e. it contains no predicates etc. The purpose of object is to be a universal base-type of all objects.

Open Qualification
Open qualifications are used to make references to class level entities more convenient. The open section brings the names of one scope into another scope, so that these can be referenced without qualification. Open has no effect on the names of object members as these can only be accessed by means of an
Visual Prolog 7.3 Language Reference Page 16 / 147

object anyway. But names of class members, domains, functors and constants can be accessed without qualification. When names are brought into a scope in this way it may happen that some names becomes ambiguous (see Scoping). Open sections have only effect in the scope in which they occur. Especially this means that an open section in a class declaration has no effect on the class implementation. OpenQualification : open ScopeName-comma-sep-list

Supports Qualification
Supports qualifications can only be used in interfaceDefinition and classImplementation. Supports qualifications are used for two things:
n

specifying that one interface A extends another interface B and, thereby, that the object type A is a subtype of the object type B declaring that the objects of a certain class "privately" have more object types, than the one specified as construction type.

supports is a transitive relation: if an interface A supports an interface B and B in turn supports C, then A also supports C. If an interface does not explicitly support any interfaces, then it implicitly supports the predefined interface object. Functionally, it makes no difference whether an interface supports a certain interface more that once (directly and/or indirectly), but it might make a representational difference for the objects. When supports is used in the implementation of a class, the result is that "This" not only can be used with the construction type, but also with any privately supported object type. SupportsQualification : supports InterfaceName-comma-sep-list SupportsQualification can only be used in interfaceDefinition and classImplementation. Notice interfaces cannot be used together in a supports qualification, if they have conflicting predicates. Predicates are conflicting if they have the same name and the arity but different origin interfaces. The origin interface of a predicate is the interface in which the predicate is literally declared, as opposed to interfaces where it is indirectly declared by a supports qualification. So it does not give conflicts, if the same interface is met twice or more in the supports chains. Example Consider the following definitions and declarations: interface aaa predicates insert : (integer X). end interface

Visual Prolog 7.3 Language Reference

Page 17 / 147

interface bbb supports aaa predicates insert : (integer X, string Comment). end interface interface c c supports aaa predicates extract : () -> integer. end interface interface dd supports aaa, bbb, cc predicates extract : (string Comment) -> integer. end interface Here is a list of all predicates found in dd (found by a depth traversal): predicates insert : (integer). % dd -> aaa insert : (integer). % dd -> bbb -> aaa insert : (integer, string). % dd -> bbb insert : (integer). % dd -> cc -> aaa extract : () -> integer. % dd -> cc extract: : (string) -> integer. % dd Some of the predicates are the same, so all in all, dd will contain the following members: predicates insert : (integer). % origin interface: aaa insert : (integer, string). % origin interface: bbb extract : () -> integer. % origin interface: cc extract : (string) -> integer. % origin interface: dd Example Consider the following interfaces: interface aaa predicates insert : (integer X). end interface interface bbb predicates insert : (integer X). end interface interface c c supports aaa, bbb end interface

% conflicting interfaces

The interface cc is illegal, because insert/1 supported in aaa has aaa as origin, whereas insert/1 supported in bbb has bbb as origin.

Visual Prolog 7.3 Language Reference

Page 18 / 147

Classes
A class declaration defines the appearance of the class to the surroundings: the surroundings can see and use exactly those entities mentioned in the class declaration. We say that the declaration of a class specifies the public part of the class. A class declaration can contain constant and domain definitions and predicate declarations. If the class states a construction type ConstructionType, then it constructs objects of that type. Object constructing classes have at least one constructor, but more can be declared. Classes that do not explicitly declare any constructors are automatically equipped with the default constructors (i.e. new/0). Objects are constructed by invoking one of constructors of the class. Constructors are also used when initializing inherited classes. Everything mentioned in a class declaration belongs to the class, rather than to objects it constructs. Everything that relates to the objects must be declared in the construction type of the objects constructed by the class. Any class declaration ClassDeclaration must have an accompanying class implementation classImplementation. The definition/implementation of predicates declared in the class declaration is provided by the class implementation. Likewise the definition of the predicates supported by the objects constructed by the class is provided by the class implementation. Both kinds of predicates can be implemented by clauses, but object predicates can also be inherited from other classes. It is important to notice that a class declaration does not state anything about code inheritance. Code inheritance is a completely private matter that can only be stated in the class implementation. (This is unlike many other object oriented programming languages, and serves to hide all implementation details in the implementation). If the class does not state a construction type ConstructionType, then the class cannot manufacture any objects; it therefore plays the role of a module rather than a "real" class. ClassDeclaration : class ClassName ConstructionType-opt ScopeQualifications Sections end class ClassName-opt

ConstructionType : : InterfaceName

ClassName : LowerCaseIdentifier See also Generic Interfaces and Classes and Monitors. The ClassName in the end of the class declaration must (if present) be identical to the one in the beginning of the class declaration. Notice that you can use the same class name ClassName as the interface name ConstructionType specified as the construction type to this class. That is you can write: class interfaceAndClassName : interfaceAndClassName Notice that both the class and the interface can declare domains and constants and these must not

Visual Prolog 7.3 Language Reference

Page 19 / 147

conflict with each other since they end up in the same name space (because they can be qualified only with the same name of the interface or the class). The ScopeQualifications must be of the kind openQualification. The Sections must be of the kinds:
n n n n n n

constantsSection domainsSection predicatesSection constructorsSection PropertiesSection conditionalSection

constructorsSections are only legal if the class states a ConstructionType. All sections contained (transitively) in conditional sections must also be of those kinds.

Visual Prolog 7.3 Language Reference

Page 20 / 147

Implementations
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 See also Generic Interfaces and Classes. 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:
n n n n

SupportsQualification OpenQualification InheritQualification DelegateQualification

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:
n n n n n n n n n

ConstantsSection ResolveQualification DelegateQualification DomainsSection PredicatesSection PropertiesSection PredicatesSection FactsSection ClausesSection


Page 21 / 147

Visual Prolog 7.3 Language Reference

ConditionalSection

constructorsSections are only legal if the class ClassName states a constructionType. Classes that states a ConstructionType are also object constructors, which construct 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 belong 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

Visual Prolog 7.3 Language Reference

Page 22 / 147

This section describes object construction and, as such, it only deals with classes that produce 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:
n n

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:
n n

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:
n

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 uninitialized 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

Visual Prolog 7.3 Language Reference

Page 23 / 147

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:
n n

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:
n n

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

Visual Prolog 7.3 Language Reference

Page 24 / 147

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 : (). 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.

% default constructor

Visual Prolog 7.3 Language Reference

Page 25 / 147

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(), aa_class::newC(C). ... 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

% create a cc_class object % invoke constructor on inherited sub-object

Visual Prolog 7.3 Language Reference

Page 26 / 147

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 : (c c 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.
Visual Prolog 7.3 Language Reference Page 27 / 147

implement aa_class facts c : (c c 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:
n n n n

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:

Visual Prolog 7.3 Language Reference

Page 28 / 147

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:

Visual Prolog 7.3 Language Reference

Page 29 / 147

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 c c c

Visual Prolog 7.3 Language Reference

Page 30 / 147

implement c c c inherits aaa clauses test() = aaa::nameThis(). end implement c c c 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

Visual Prolog 7.3 Language Reference

Page 31 / 147

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:

Visual Prolog 7.3 Language Reference

Page 32 / 147

ResolveQualification : resolve Resolution-comma-sep-list

Resolution : InterfaceResolution PredicateFromClassResolution PredicateRenameResolution PredicateExternallyResolution 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:
n

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
Visual Prolog 7.3 Language Reference Page 33 / 147

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).

Visual Prolog 7.3 Language Reference

Page 34 / 147

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.

Visual Prolog 7.3 Language Reference

Page 35 / 147

PredicateDelegation : PredicateNameWithArity to FactVariable_of_InterfaceType To delegate a predicate to an object passed with the fact variable:
n

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 : (). p2 : (). 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 O_cc O_dd O_dd O_dd

= bb_class::new(), = cc_class::new(), = dd_class::new(O_bb, O_cc), : p1(), : p2().

% This p1 from O_bb object % 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().

Visual Prolog 7.3 Language Reference

Page 36 / 147

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:
n

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.

Visual Prolog 7.3 Language Reference

Page 37 / 147

Generic Interfaces and Classes


Interfaces and classes can be parametrized with type parameters so that they can be used in different instantiations in different contexts. This section must be considered as an extension to the individual sections about:
n n n

Interfaces Classes Implementations

The pragmatic reason to use generic classes and interfaces is to declare parametrized object facts and implement operations on these facts. As illustrated in the Queue example below.

Example: Queue
Consider this interface interface queue_integer predicates insert : (integer Value). tryGet : () -> integer Value. end interface queue_integer An object of this type is a queue of integers, if you replace "integer" with "string" you would have a type describing queues of strings. A generic interface can be used to describe all such interfaces in a single interface definition: interface queue{@Elem} predicates insert : (@Elem Value). tryGet : () -> @Elem Value determ. end interface queue @Elem is a scope type variable (distinguished from local type variables by the @). queue{integer} represents integer-queues; queue{string} represents string-queues; and so forth. We can declare a generic queue class like this: class queueClass{@Elem} : queue{@Elem} end class queueClass queueClass{@Elem} constructs objects type queue{@Elem} for any instantiation of @Elem. The implementation can look like this:

Visual Prolog 7.3 Language Reference

Page 38 / 147

implement queueClass{@Elem} facts queue_fact : (@Elem Value). clauses insert(Value) :assert(queue_fact(Value)). clauses tryGet() = Value :retract(queue_fact(Value)), !. end implement queueClass This piece of code illustrates how to create an integer queue and insert an element in it: ..., Q = queueClass{integer}::new(), Q:insert(17), ... It is not necessary to apply the type explicitly, instead the compiler can infer it from the context: ..., Q = queueClass::new(), Q:insert(17), ... The compiler sees that Q must be an integer queue, because we insert 17 into it.

Generic Interfaces
Syntax Generic interfaces have a list of type parameters: InterfaceDeclaration : interface InterfaceName { ScopeTypeVariable-comma-sep-list-opt } ScopeQualifications Sections ... ScopeTypeParameter : @ UppercaseName The scope type parameters can be used in any declaration/definition in the interface. Semantics A generic interface defines all the interfaces that can be obtained by instantiating the type parameters with actual types. The scope type parameters from the opening are bound in the entire interface. Restrictions Then closing name should not have parameters: interface xxx{@A} ... end interface xxx % no parameters here It is illegal to use same interface name for interfaces with different arity (in the same namespace): interface xxx % xxx/0 ... end interface xxx
Visual Prolog 7.3 Language Reference Page 39 / 147

interface xxx{@A, @B} % error: Several classes, interfaces and/or namespaces have the same name 'xxx' ... end interface xxx Parameters can be used in supported interfaces: interface xxx{@P} supports yyy{@P} % legal: @P is bound ... end interface xxx interface xxx supports yyy{@P} % illegal: @P must be bound ... end interface xxx Supported interfaces can be instantiated with any type expressions (as long as parameters are bound): interface xxx{@A} supports yyy{integer, @A*} ...

Generic Classes
Syntax Generic classes have a list of type parameters, and constructs objects of an interface type uses the these parameters. ClassDeclaration : class ClassName { ScopeTypeVariable-comma-sep-list-opt } ConstructionType ScopeQualifications ... ScopeTypeParameter : @ UppercaseName ConstructionType : : TypeExpression The construction type must be generic (i.e. a generic interface). Semantics A generic class declares a class with a generic constructor. The type of the constructed object will be inferred from the usage of the constructor. Restrictions Then closing name should not have parameters: class xxx{@A} : xxx{@AAA} ... end class xxx % no parameters here It is illegal to use same class name for class with different arity (in the same namespace):

Visual Prolog 7.3 Language Reference

Page 40 / 147

class xxx % xxx/0 ... end class xxx class xxx{@A} : yyy{@A} % error: Several classes, interfaces and/or namespaces have the same name 'xxx' ... end class xxx If a class and interface can have the same name, the class must construct objects of that interface. interface xxx{@A} ... end interface xxx class xxx{@Q, @P} : object % error: Several classes, interfaces and/or namespaces have the same name 'xxx' ... end class xxx Parameters in the construction type, etc must be bound: class bbb : xxx{@Q} % error: Free parameter '@Q' is used in type expression ... All the parameters from the class must be used in the construction type: class xxx{@P} : object % error: Unused type parameter '@P' ... In class declarations scope parameter can only be used in constructors, domains and constants. class xxx{@P} : xxx{@P} domains list = @P*. % legal constants empty : @P* = []. % legal constructors new : (@P Init). % legal predicates p : (@P X). % error: Scope parameter '@P' used in a class entity end class xxx

Generic Implmentations
Syntax Generic implementations have a list of type parameters. ClassImplementation : implement ClassName { ScopeTypeVariable-comma-sep-list-opt } ScopeQualifications Sections ... ScopeTypeParameter : @ UppercaseName Semantics

Visual Prolog 7.3 Language Reference

Page 41 / 147

A generic class declares a class with a generic constructor. The type of the constructed object will be inferred from the usage of the constructor. Restrictions Then closing name should not have parameters: implement xxx{@A} ... end implement xxx % no parameters here The parameters must be the same as in the corresponding class declaration and have same order. class xxx{@A} : aaa{@A} ... end class xxx implement xxx{@B} % error: The parameter '@B' is not the same as in the declaration '@A' ... end implement xxx In class implementations scope parameter can be used in constructors, domains, constants and in object entities (i.e. object facts, object predicates and object properties). implement xxx{@P} domains list = @P*. % legal constants empty : @P* = []. % legal constructors new : (@P Init). % legal predicates op : (@P X). % legal class predicates cp : (@P X). % error: Scope parameter '@P' used in a class entity facts ofct : (@P). % legal class facts cfct : (@P). % error: Scope parameter '@P' used in a class entity ... end implement xxx

Visual Prolog 7.3 Language Reference

Page 42 / 147

Monitors
A monitor is a language construction to synchronize two or more threads that use a shared resource, usually a hardware device or a set of variables. The compiler transparently inserts locking and unlocking code to appropriately designated procedures, instead of the programmer having to access concurrency primitives explicitly. Visual Prolog monitor entrances can be controlled by guard predicates (conditions).

Syntax
Monitor interfaces and monitor classes are scopes: Scope : one of ... MonitorInterface MonitorClass ... A monitor interface is defined by writing the keyword monitor in front of a regular interface definition: MonitorInterface : monitor IntertfaceDefinition A monitor class is declared by writing the keyword monitor in front of a regular class declaration: MonitorClass : monitor ClassDeclaration Monitor classes and interfaces cannot declare multi and nondeterm predicate members.

Restrictions
n n n

A regular interface cannot support a monitor interface A monitor class cannot construct objects. It is not legal to inherit from a monitor (i.e. from a class that implements a monitor interface).

Semantics
The predicates and properties declared in a monitor are the entrances to the monitor. A thread enters the monitor through an entrance and is in the monitor until it leaves that entrance again. Only one thread is allowed to be in the monitor at the time. So each entry is protected as a critical region. The semantics is simplest to understand as a program transformation (which is how it is implemented). Consider this academic example: monitor class mmmm predicates e1 : (a1 A1). e2 : (a2 A2). ... en : (an An). end class mmmm

Visual Prolog 7.3 Language Reference

Page 43 / 147

%----------------------------------------implement mmmm clauses e1(A1) :- <B1>. clauses e2(A2) :- <B2>. ... clauses en(An) :- <Bn>. end implement mmmm Where <B1>, <B2>, ..., <Bn> are clause bodies. This code corresponds to the following "normal" code: class mmmm predicates e1 : (a1 A1). e2 : (a2 A2). ... en : (an An). end class mmmm %----------------------------------------implement mmmm class facts monitorRegion : mutex := mutex::create(false). clauses e1(A1) :_W = monitorRegion:wait(), try <B1> finally monitorRegion:release() end try. clauses e2(A2) :_W = monitorRegion:wait(), try <B2> finally monitorRegion:release() end try. ... clauses en(An) :_W = monitorRegion:wait(), try <Bn> finally monitorRegion:release() end try. end implement mmmm So each monitor class is extended with a mutex, which is used to create a critical region around each entry body. The code for monitor objects is similar, except that the mutex object is owned by the object.

Guards
Consider a monitor protected queue: some threads (producers) inserts elements in the queue and others (consumers) pick-out elements. However, you cannot pick-out elements if the queue is

Visual Prolog 7.3 Language Reference

Page 44 / 147

empty. If we implement the queue using a monitor, the "pick-out" entry could be determ, failing if the queue is empty. But then the consumers would have to "poll" the queue until an element can be obtained. Such polling uses system resources, and normally it is desirable to avoid polling. This problem can be solved by guard predicates. Each entry can have a guard associated in the implementation. The guard is added as a special guard-clause before the other clauses of the entry. Clause : one of ... GuardClause.

GuardClause : one of LowerCaseIdentifier guard LowerCaseIdentifier . LowerCaseIdentifier guard AnonymousPredicate . Example The guard can be the name of a predicate clauses remove guard remove_guard. remove() = ... Example The guard can also be an anonymous predicate clauses remove guard { :- element_fact(_), ! }. remove() = ...

The guard predicates are evaluated when the monitor is created. For monitor classes this means at program start, for object predicates this is immediately after the construction of the object. The guard predicates are also evaluated whenever a tread leaves the monitor. But they are not evaluated at any other time. If a certain guard succeeds the corresponding entry is open, if it fails the entry is closed. It is only possible to enter open entries. Example Here is a queue class that solves the pick-out problem using a guard predicate on the remove operation: monitor class queue predicates insert : (integer Element). predicates remove : () -> integer Element. end class queue %----------------------------------------implement queue class facts element_fact : (integer Element) nondeterm. clauses insert(Element) :assert(element_fact(Element)).
Visual Prolog 7.3 Language Reference Page 45 / 147

clauses remove guard remove_guard. remove() = Element :retract(element_fact(Element)), !; common_exception::raise_error(common_exception::classInfo, predicate_name(), "The guard should have ensured that the queue is not empty"). predicates remove_quard : () determ. clauses remove_guard() :element_fact(_), !. end implement queue Notice that remove is a procedure, because threads that call remove will wait until there is an element for them. The guard predicate remove_guard succeeds if there is an element in the queue. So remove_guard is evaluated each time a thread leaves the monitor, and the element_fact fact database can only be changed by a thread that is inside the monitor. Therefore the guard value stays sensible all the time (i.e. when there are no threads in the monitor). It is important to ensure such "stays sensible" condition for guards. Guard predicates are handled in the transformation mentioned above. The queue example is effectively the same as this "monitor-free" code: class queue predicates insert : (integer Element). predicates remove : () -> integer Element. end class queue %----------------------------------------implement queue class facts monitorRegion : mutex := mutex::create(false). remove_guard_event : event := event::create(true, toBoolean(remove_guard())). element_fact : (integer Element) nondeterm. clauses insert(Element) :_W = monitorRegion:wait(), try assert(element_fact(Element)) finally setGuardEvents(), monitorRegion:release() end try. clauses remove() = Element :_W = syncObject::waitAll([monitorRegion, remove_guard_event]), try retract(element_fact(Element)), !; common_exception::raise_error(common_exception::classInfo, predicate_name(), "The guard should have ensured that the queue is not empty") finally setGuardEvents(), monitorRegion:release() end try.

Visual Prolog 7.3 Language Reference

Page 46 / 147

class predicates remove_guard : () determ. clauses remove_guard() :element_fact(_), !. class predicates setGuardEvents : (). clauses setGuardEvents() :remove_guard_event:setSignaled(toBoolean(remove_guard())). end implement queue An event is created for each guard predicate; this event is set to signaled if the guard predicate succeeds. As mentioned it is set during the creation of the monitor and each time a predicate leaves the monitor (before it leaves the critical region). When entering an entry the threads waits both for the monitorRegion and for the guard event to be in signalled state. In the code above the initialization of the class itself and the guard events are done in an undetermined order. But actually it is ensured that the guard events are initialized after all other class/object initialization is performed.

Examples of practical usage


This section shows a few cases where monitors are handy. Writing to a log file Several threads needs to log information to a single log file. monitor class log properties logStream : outputStream. predicates write : (...). end class log %----------------------------------------implement log class facts logStream : outputStream := erroneous. clauses write(...) :logStream:write(time::new():formatShortDate(), ": "), logStream:write(...), logStream:nl(). end implement log The monitor ensures that writing of a log lines are not mixed with each other, and that stream changes only takes place between writing of log lines. Shared output streams This monitor can be used to thread protect the operations of an output stream: monitor interface outputStream_sync supports outputStream end interface outputStream_sync

Visual Prolog 7.3 Language Reference

Page 47 / 147

%----------------------------------------class outputStream_sync : outputStream_sync constructors new : (outputStream Stream). end class outputStream_sync %----------------------------------------implement outputStream_sync delegate interface outputStream to stream facts stream : outputStream. clauses new(Stream) :- stream := Stream. end implement outputStream_sync You should realize however that with code like this: clauses write(...) :logStream:write(time::new():formatShortDate(), ": "), logStream:write(...), logStream:nl(). consists of three separate operations, so it can still be the case (fx) that two threads first write the time and then one writes the "...", etc. Queue The queue above is fine, but actually it may be better to create queue objects. Using generic interfaces we can create a very general queue: monitor interface queue{@Elem} predicates enqueue : (@Elem Value). predicates dequeue : () -> @Elem Value. end interface queue %----------------------------------------class queue{@Elem} : queue{@Elem} end class queue %----------------------------------------implement queue{@Elem} facts value_fact : (@Elem Value). clauses enqueue(V) :assert(value_fact(V)). clauses dequeue guard { value_fact(_), ! }. dequeue() = V :value_fact(V), !. dequeue() = V :common_exception::raise_error(....). end implement queue Notice that PFC contains a similar class monitorQueue already.

Visual Prolog 7.3 Language Reference

Page 48 / 147

References
n

wikipedia:Monitor (synchronization)

Visual Prolog 7.3 Language Reference

Page 49 / 147

Namespaces
Namespaces can be used to avoid name clashes, without having to use long strange names. The names in two different namespaces will never clash, but it may be necessary to qualify references with the namespace (or part of it) to resolve ambiguities. A namespaces are declared and defined implicitly using NamespaceEntrance'es: NamespaceEntrance: namespace NamespaceIdentifier

NamespaceIdentifier: one of LowercaseIdentifier LowercaseIdentifier \ NamespaceIdentifier In short a NamespaceIdentifier is a sequence of lowercase identifiers separated by backslashes.

Namespace Entrances and Regions


Namespace entrances divide source files into namespace regions. A namespace entrance marks the beginning of a namespace region, which ends at the next namespace entrance or the end of the file. Every file starts in the root namespace. Namespace regions are not influenced by #include directives, meaning:
n

Namespace entrances in an #include-file does not change the namespace region in the including file Any file starts in the root namespace (also if it is included inside a namespace region in another file).

Any interface, class and implementation that is meet inside a namespace region belongs to that namespace. Example class aaa end class aaa namespace xxx class bbb end class bbb namespace xxx\yyy class c c c end class c c c This file is divided in three regions (assuming that it is a complete file). The first region is in the root namespace (\), the second region belongs to the xxx namespace and the third region belongs to the xxx\yyy namespace. Subsequently, the class aaa belongs to the root namespace, the class bbb belongs to the namespace xxx and finally the class ccc belongs to the namespace xxx\yyy.

Visual Prolog 7.3 Language Reference

Page 50 / 147

Referencing names in namespaces


If ccc is a class in the namespace xxx\yyy, then the full name of ccc is \xxx\yyy\ccc. The leading backslash indicates that we start from the root namespace. A class/interface can always be uniquely referenced using its full name. Open namespaces The full names are not always convenient and therefore it is possible to use shorter names by opening namespaces. ScopeQualification: one of OpenQualification ... OpenQualification: one of open NamespaceIdentifier \ ... Opening a namespace is distinguished from opening a class/interface by a trailing backslash. Example class aaa open xxx\yyy\ ... end class aaa The namespace xxx\yyy is opened inside aaa. When a namespace is open that part of a full name can be left out. Example A domains with the full name \xxx\yyy\zzz\ccc::ddd can be as referenced zzz\ccc::ddd inside aaa because xxx\yyy is open. Notice that the short name does not start with a backslash; A name starting with a backslash is always a full name. The namespace that a certain scope (i.e. interface/class/implementation) belongs to is (implicitly) open inside that scope.

Visual Prolog 7.3 Language Reference

Page 51 / 147

Program Sections
Sections are used to declare and define entities in scopes. Section : ConstantsSection DomainsSection PredicatesSection ConstructorsSection PropertiesSection FactsSection ClausesSection ConditionalSection Section: ConstantsSection, DomainsSection, ConstructorsSection, FactsSection, ClausesSection, PropertiesSection, ConditionalSection Not all sections can occur in all kinds of scopes, please refer to the description of Interfaces, Class Declarations, and Class Implementations for further details. Conditional sections are described in Conditional Compilation.

Visual Prolog 7.3 Language Reference

Page 52 / 147

Domains
Domains Sections
A domain section defines a set of domains in the current scope (see Interface, Class Declaration, and Class Implementation). DomainsSection: domains DomainDefinition-dot-term-list-opt

Domain Definitions
A domain definition defines a named domain in the current scope. DomainDefinition: DomainName FormalTypeParameterList-opt = TypeExpression If the domain on the right hand side denotes an interface or a compound domain, then the defined domain is synonym (i.e. identical) to the type expression. Otherwise the defined domain becomes a subtype of the domain denoted by the type expression. Here a domain name DomainName should be a lower case identifier. There are certain places where you must use a domain name rather than a type expression:
n n n

as a declaration of a formal argument type; as a type of a constant or a fact variable; as a type in a list domain.

Type Expressions
A type expression denotes a type. TypeExpression: TypeName CompoundDomain ListDomain PredicateDomain IntegralDomain RealDomain TypeVariable TypeApplication Type Names A type name is either an interface name or the name of a value domain. We use the term value domain to specify domains whose elements are immutable (unchangeable). Here we can say that objects, belonging to domains correspondent to interface names, have mutable state and terms of any other domains are immutable. So actually value types are everything except object types. A type name (obviously) denotes the type corresponding to the name of an existing domain. TypeName: InterfaceName DomainName ClassQualifiedDomainName

Visual Prolog 7.3 Language Reference

Page 53 / 147

InterfaceName: LowercaseIdentifier

DomainName: LowercaseIdentifier

ClassQualifiedDomainName: ClassName::DomainName

ClassName: LowercaseIdentifier Here InterfaceName is an interface name, DomainName is a value domain name, and ClassName is a class name. Example domains newDomain1 = existingDomain. newDomain2 = myInterface. In this example the domain name existingDomain and the interface name myInterface are used to define new domains. Compound Domains Compound domains (also known as algebraic data types) are used to represent lists, trees, and other tree structured values. In its simple forms compound domains are used to represent structures and enumeration values. Compound domains can have a recursive definition. They can also be mutually/indirectly recursive. CompoundDomain: Alignment-opt FunctorAlternative-semicolon-sep-list>

Alignment: align IntegralConstantExpression Here IntegralConstantExpression is an expression, which must be compile time evaluated to an integral value. A compound domain declaration declares a list of functor alternatives with optional alignment. Alignment must be 1, 2 or 4. If a compound domain consists of one functor alternative, then it is considered as structure and has representation, which is binary compatible with the appropriate structure in language C. FunctorAlternative: FunctorName FunctorName ( FormalArgument-comma-sep-list-opt ) Here FunctorName is the name of a functor alternative it should be a lower case identifier. FormalArgument: TypeExpression ArgumentName-opt

Visual Prolog 7.3 Language Reference

Page 54 / 147

Here ArgumentName can be any upper case identifier. The compiler ignores it. Compound domains have no subtype relations to any other domains. If a domain is defined as being equal to a compound domain, then these two domains are synonym types rather than subtypes. Meaning that they are just two different names for the same type. Example domains t1 = ff(); gg(integer, t1). t1 is a compound domain with two alternatives. The first alternative is the null-ary functor ff, while the second alternative is the two-ary functor gg, which takes an integer and a term of the domain t1 itself as arguments. So the domain t1 is recursively defined. The following expressions are terms of the domain t1: ff() gg(77, ff()) gg(33, gg(44, gg(55, ff()))) Example domains t1 = ff(); gg(t2). t2 = hh(t1, t1). t1 is a compound domain with two alternatives. The first alternative is the null-ary functor ff, while the second alternative is the unary functor gg, which takes a term of the domain t2 as argument. t2 is a compound domain with one alternative the functor hh, which takes two t1 terms as argument. So the domains t1 and t2 are mutually recursive. The following are terms in the domain t1: ff() gg(hh(ff(), ff())) gg(hh(gg(hh(ff(), ff())), ff())) ggg(hh(ff(), g(hh(ff(), ff())))) gg(hh(gg(hh(ff(), ff())), gg(hh(ff(), ff())))) Example In this example t1 and t2 are synonym types. domains t1 = f(); g(integer). t2 = t1. Normally, it is not necessary to use empty parenthesis after null-ary functors. But in a domain definition consisting only of a single null-ary functor, empty parenthesis are required to distinguish it from a synonym/subtype definition. Example
Visual Prolog 7.3 Language Reference Page 55 / 147

t1 is a compound domain with a single null-ary functor, whereas t2 is defined to be synonym to t1. domains t1 = f(). t2 = t1. List Domains List domains represent sequences of values of a certain domain. Thus, all elements in a T list must be of type T. ListDomain: TypeName * T* is the type of lists of T elements. The following syntax is used for lists: ListExpression: [ Term-comma-sep-list-opt ] [ Term-comma-sep-list | Tail ]

Tail: Term Here Tail is a term which should have a value of the ListDomain type. Each Term should be of typeName type. Actually, lists are just compound domains with two functors: [] denoting the empty list and the mixfix functor [HD|TL] denoting the list with head HD and tail TL. The head must be of the underlying element type, whereas the tail must be a list of relevant type. Lists are however syntactically sugared. [E1, E2, E3, ..., En | L ] is shorthand for [E1 |[ E2 |[ ...[ En | L ]...}}] [E1, E2, E3, ..., En] is shorthand for [E1, E2, E3, ..., En |[}}, which in turn is shorthand for [E1 | [ E2 |[ ...[ En | [] ]...}}] Predicate Domains Values of a predicate domain are predicates with the same "signature", i.e. the same argument and return types, the same flow pattern and the same (or stronger) predicate mode. A predicate that returns a value is called a function, whereas a predicate that does not return a value is sometimes called an ordinary predicate, to stress that it is not a function. PredicateDomain: ( FormalArgument-comma-sep-list-opt ) ReturnArgument-opt PredicateModeAndFlow-list-opt CallingConvention-opt

Visual Prolog 7.3 Language Reference

Page 56 / 147

FormalArgument: PredicateArgumentType VariableName-opt Ellipsis

ReturnArgument: -> FormalArgument

PredicateArgumentType: TypeName AnonymousIdentifier

VariableName: UpperCaseIdentifier Predicate domains can have Ellipsis argument as the last FormalArgument in the FormalArgument-comma-sep-list. Predicate domains can have AnonymousIdentifier as a predicateArgumentType to specify that the argument can be of any type. Currently, predicate domains with ellipsis can only be used in predicate declarations. Predicate domains that are used in domain definitions can at most state one flow. PredicateModeAndFlow: PredicateMode-opt FlowPattern-list-opt Predicate Mode The specified predicate mode applies for each member of a flow pattern list following it. PredicateMode: one of erroneous failure procedure determ multi nondeterm Predicate modes can be described by the following sets: erroneous = {} failure = {Fail} procedure = {Succeed} determ = {Fail, Succeed} multi = {Succeed, BacktrackPoint} nondeterm = {Fail, Succeed, BacktrackPoint} If Fail is in the set it means that the predicate can fail. If succeed is in the set it means that the predicate can succeed. If BacktrackPoint is in the set it means that the predicate can return with an active backtrack point in it. If such a set, say failure, is a subset of another set, say nondeterm, then we say that the mode is stronger than the other, i.e. failure is stronger than nondeterm.
Visual Prolog 7.3 Language Reference Page 57 / 147

A predicate domain actually contain all predicates (with correct type and flow), which have the mode specified or a stronger mode. It is illegal to state a predicate mode for constructors, they always have the procedure mode. Omitting of a predicate mode means procedure. Omitting of flows means that all arguments are input. Notice that, in difference to Visual Prolog v. 5.x, inside implementations (i.e. for a local predicates) the needed flows and modes are NOT derived from the usages of the predicate. Now in declarations of for local predicates omitting the predicate mode means procedure and omitting flows means that all arguments are input. If inside an implementation you do not want to specify all possible flows of a predicate usage explicitly, you still can deliver this duty to the compiler. For this task inside class implementations you can use the special flow pattern anyflow. In this case the compiler during the compilation will derive the needed flows from usages of the predicate. But if the optional preceding predicate mode is omitted before the anyflow flow pattern, then the procedure mode is always assumed. Flow Pattern The flow pattern defines the input/output direction of the arguments, which in combination with functor domains can be structures with parts of a single argument being input and other parts of the same argument being output. A flow pattern consists of a sequence of flows, each flow corresponds to an argument (fist flow to first argument, etc). FlowPattern: ( Flow-comma-sep-list-opt ) AnyFlow

Flow: one of i o FunctorFlow ListFlow Ellipsis Ellipsis flow must match an ellipsis argument and can therefore be only the last flow in the flow pattern. Ellipsis: ... A functor flow FunctorFlow states a functor and flows of each of the components of that flow. The functor must of course be in the domain of the corresponding argument. FunctorFlow: FunctorName ( Flow-comma-sep-list-opt ) A functor flow declaration cannot contain ellipsis flow. List flows are just like functor flows, but with the same syntactic sugaring as the list domain.

Visual Prolog 7.3 Language Reference

Page 58 / 147

ListFlow: [ Flow-comma-sep-list-opt ListFlowTail-opt]

ListFlowTail: | Flow A list flow cannot contain ellipsis flow. When declaring a predicate the flow can be omitted. Inside an implementation (i.e. for a local predicate) the needed flows are derived from the usages of the predicate. Inside an interface or a class declaration (i.e. for a public predicate) omitting flows means that all arguments are input. Special flow pattern anyflow can be stated only in declarations of local predicates (i.e. in predicate declarations inside the implementation of a class). It means that the exact flow pattern will be evaluated during the compilation. If the optional preceding predicate mode is omitted for this flow pattern, then it assumes to be a procedure. Example domains pp1 = (integer Argument1). pp1 is a predicate domain. The predicates that have type pp1 takes one integer argument. Since no flow-pattern is stated the argument is input, and since no predicate mode is mentioned the predicates are procedure. Example domains pp2 = (integer Argument1) -> integer ReturnType. Predicates of type pp2 take one integer argument and returns a value of type integer. Therefore, pp2 is actually a function domain and the predicates that have type pp2 are actually functions. Since no flow-pattern is stated the argument is input and since no predicate mode is mentioned the predicates are procedure. Example predicates ppp : (integer Argument1, integer Argument2) determ (o,i) (i,o) nondeterm (o,o). The predicate ppp takes two integer arguments. It exists in three flow variants: (o,i) and (i,o), which are determ, and (o,o), which is nondeterm. Calling Convention The calling convention determines how arguments, etc. are passed to the predicate, it also determines how the link name is derived from a predicate name. CallingConvention: language CallingConventionKind

Visual Prolog 7.3 Language Reference

Page 59 / 147

CallingConventionKind: one of c stdcall apicall prolog If a calling convention is not stated, then the prolog convention is assumed. The prolog calling convention is the standard convention used for Prolog predicates. The calling convention c follows the C/C++ standard calling convention. The link name of a predicate is created from the predicate name by adding a leading underscore (_). The calling convention stdcall uses the c link name strategy but it uses the different argument and stack handling rules. The following table shows the implementation of stdcall calling convention: Feature Argument-passing order Argument-passing convention Stack-maintenance responsibility Name-decoration convention Case-translation convention Right to left. By value, unless a compound domain term is passed. So it cannot be used to predicates with variable number of arguments. Called predicate pops its own arguments from the stack. An underscore (_) is prefixed to the predicate name. No case translation of the predicate name is performed. Implementation

The calling convention apicall uses the same argument and stack handling rules as stdcall, but for convenience to call MS Windows API functions apicall uses the naming conventions that are used by most MS Windows API functions. According to apicall naming conventions the link name of a predicate is constructed as follows:
n n n

n n

an leading underscore (_) is prefixed to the predicate name; the predicate name in which the first letter is changed in to a capital letter; the 'A', the 'W' or nothing is suffixed, if the arguments and the return type indicate an ANSI, Unicode or neutral predicate, respectively; the '@' is suffixed; the number of bytes pushed on the call stack is suffixed.

Example predicates predicateName : (integer, string) language apicall The argument types of this predicate indicates that it is a Unicode predicate (as string is the domain of Unicode strings). An integer and a string each occupies 4 bytes on the call stack and, therefore, the link name becomes: _PredicateNameW@8 If apicall is used together with the "as" construction the name stated in the "as" construction is decorated in the same manner. apicall can only be used directly in a predicate declaration, not in a predicate domain definition. In predicate domain definitions stdcall, must be used instead. The following table compares implementations of c, apicall, and stdcall calling conventions (the prolog calling convention has the special implementation, which is not discussed here):
Visual Prolog 7.3 Language Reference Page 60 / 147

Keyword

Stack cleanup

Predicate name case-translation

Link predicate name decoration convention An underscore (_) is prefixed to the predicate name.

Calling predicate pops the None. arguments from the stack. Called predicate pops its own arguments from the stack. Called predicate pops its own arguments from the stack.

stdcall

None.

An underscore (_) is prefixed to the predicate name.

apicall

An underscore (_) is prefixed to the name. The first letter of the The first letter is changed to the upper case. predicate name is The 'A', the 'W' or nothing is suffixed. The changed to the sign @ is suffixed. The (decimal) number of capital letter. bytes in the argument list is suffixed.

Visual Prolog notion of predicate domains covers both class and object members. Class members are handled straight forward, but the handling of object members requires attention. The invocation of an object predicate will get "back" in the context of the object to which the member belongs. Example Assume the following declarations: interface actionEventSource domains actionListener = (actionEventSource Source) procedure (i). predicates addActionListener : (actionListener Listener) procedure (i). ... end interface Also assume a class button_class which supports the actionEventSource. The event is sent when the button is pressed. In myDialog_class class, which implements a dialog, I create a button and I want to listen to its action events, so that I can react on button presses: implement myDialog_class clauses new() :OkButton = button_class::new(...), OkButton:addActionListener(onOk), ... facts okPressed : () determ. predicates onOk : actionListener. clauses onOk(Source) :assert(okPressed()). end implement The important thing about the example is that onOk is an object member and that, when the button is pressed, the invocation of the registered onOk will bring us back in the object that owns onOk. This means that we have access to the object fact okPressed, so that we can assert it. Format Strings A formal parameter to a predicate can be marked as format string using the attribute formatString. The format string can contain ordinary characters which are printed without modification, and format fields,that%beginswiththepercent'%'sign.Ifthepercentsignisfollowed%bysomeunknown character (not the format specifier) -then%thischaracterwillbeprintedwithoutmodifications.

Visual Prolog 7.3 Language Reference

Page 61 / 147

predicates writef : (string Format [formatstring], ...) The format fields specification is: [-][0][width][.precision][type] All fields are optional.

procedure (i,...).

[-] Hyphen indicates that the field is to be left justified; right justified is the default. Having no effect when width value is not set, or the number of characters in the actual value is greater than width value. [0] Zero before width means for values that zeros will be added until the minimum width is reached. If 0(zero) and -(hyphen) appear, the 0 is ignored [width] Positive decimal number specifying a minimum field size. If the number of characters in the actual value is less than width value - then the required number of space ' ' characters will be added before the value (or after it, if '-' field was set). No changes occurs if number of characters in the actual value is greater than the width value. [.precision] The point '.' with the following unsigned decimal number can specify either the precision of a floating-point image or the maximum number of characters to be printed from a string. [type] Specifies other format then the default for the given. For example, in the type field, you can give a specifier that says an integer will be formatted as an unsigned. The possible values are: Format real's in fixed-decimal notation (such as 123.4 or 0.004321). This is the default for real's. Format real's in exponential notation (such as 1.234e+002 or 4.321e-003). Format real's in the shortest of f and e format, but always in e format if exponent of the value is less than -4 or greater than or equal to the precision. Trailing zeros are truncated.

f e g

d or Format as a signed decimal number. D u or Format as an unsigned integer. U x or Format as a hexadecimal number. X o or Format as an octal number. O c B R P s Format as a char. Format as the Visual Prolog binary type. Format as a database reference number. Format as a procedure parameter. Format as a string.

Integral Domains Integral domains are used for representing integral numbers. They are divided in two main categories for signed and unsigned numbers. Integral domains can also have different representation size. The predefined domains integer and unsigned represent signed and unsigned numbers with natural representation length for the processor architecture (i.e. 32bit on a 32bit machine, etc).

Visual Prolog 7.3 Language Reference

Page 62 / 147

IntegralDomain: DomainName-opt IntegralDomainProperties If a DomainName is stated in front of the IntegralDomainProperties, then this domain must itself be an integral domain and the resulting domain will be child-type (i.e. subtype) of this domain. In that case IntegralDomainProperties may not violate the possibility of being a subtype, i.e. the range cannot be extended and the size cannot be changed. IntegralDomainProperties: IntegralSizeDescription IntegralRangeDescription-opt IntegralRangeDescription IntegralSizeDescription-opt IntegralSizeDescription: bitsize DomainSize DomainSize: IntegralConstantExpression An integral size description declares the size DomainSize of the integral domain, measured in bits. The compiler implement such representation to the integral domain, which has no less than the specified number of bits. The value of DomainSize should be positive and no greater than the maximal value supported by the compiler. If integral size description is omitted, then it will become the same as the parent domain. If there is no parent domain, it will become the natural size for the processor. IntegralRangeDescription: [ MinimalBoundary-opt .. MaximalBoundary-opt ] MinimalBoundary: IntegralConstantExpression MaximalBoundary: IntegralConstantExpression An integral range description declares the minimal MinimalBoundary and the maximal MaximalBoundary limits for the integral domain. If a limit is omitted, then the range of the parent domain is used. If there is no parent domain, then the DomainSize is used to determine respectively maximum or minimum value. Notice that the specified minimum value should not exceed the specified maximum value. That is: MinimalBoundary < MaximalBoundary = Also the minimal MinimalBoundary and the maximal MaximalBoundary limits should satisfy the limits implied by the specified bit size bitsize. The domain bit size DomainSize value and values of the minimal MinimalBoundary and the maximal MaximalBoundary limits must be calculated while compiling time. Real Domains Real domains are used to represent numbers with fractional parts (i.e. floating point numbers). Real domains can be used to represent very large and very small numbers. The built-in domain real have the natural precision for the processor architecture (or the precision given by the compiler). RealDomain: DomainName-opt RealDomainProperties
Visual Prolog 7.3 Language Reference Page 63 / 147

If a DomainName is stated in front of the RealDomainProperties, then this domain must itself be a real domain and the resulting domain will be a subtype of this domain. In that case RealDomainProperties may not violate the possibility of being a subtype, i.e. the range cannot be extended and the precision cannot be increased. RealDomainProperties: one of RealPrecisionDescription RealRangeDescription-opt RealRangeDescription RealPrecisionDescription

RealPrecisionDescription: digits IntegralConstantExpression The real precision description declares precision of the real domain, measured in number of decimal digits. If precision is omitted then it will become the same as for the parent domain. If there is no parent domain, then it will be the natural precision for the processor or given by the compiler (in Visual Prolog v.6 the compiler limit is 15 digits). Precision have an upper and a lower limits given by the compiler, if the precisions larger than that limit is used the numbers will only obtain the processor (compiler) specified precision anyway. RealRangeDescription: [ MinimalRealBoundary-opt .. MaximalRealBoundary-opt ] MinimalRealBoundary: RealConstantExpression MaximalRealBoundary: RealConstantExpression Here RealConstantExpression is an expression, which must be compile time evaluated to a floating point value. That is the real domain precision and limits must be calculated while compiling time. The real range description declares minimal and maximal limits for the real domain. If a limit is omitted then it will be the same as for the parent domain. If there is no parent domain then the largest possible range for the precision will be used. Notice that the specified minimum value should not exceed the specified maximum value. That is: MinimalBoundary < MaximalBoundary = Generic Domains This section contains the formal syntax for generic domains, for a more complete introduction to generics please see the section Generics. FormalTypeParameterList: TypeVariable-comma-sep-list-opt A formalTypeParameterList is a list of typeVariables TypeVariable: UpperCaseIdentifier A TypeVariable is an upper case identifier. In a domain declaration the type variable must be bound

Visual Prolog 7.3 Language Reference

Page 64 / 147

in the FormalTypeParameterList on the left hand side of the domain definition. In a predicate declaration all free type variables are implicitly bound and scoped to that predicate declaration. TypeApplication: TypeName {TypeExpression-comma-sep-list-opt } A TypeApplication is the application of a typeName to a list of types. The type name must be generic and the number of formal type parameters must match the number of type expressions.

Universal and Root Types


Visual Prolog uses some internal types, called root types and universal types. Universal Types A number literal like 1 does not have any particular type, it can be used as a value of any type that contains 1, including real types. We say that 1 have a universal type. Having a universal type means that it have any type, which can represent its value. Arithmetic operations also return universal types. Root Types Arithmetic operations are very liberal with their operand requirements: You can add integers of any integer domain with each other. We say that arithmetic operands takes root types as arguments. The integer root type is super-type of any integer type (regardless that it is not mentioned in their declarations). Hence any integer type can be converted to the integer root type, and, since the arithmetic operations exist for the root types, it means one of them will work on any integer domains. The actual number of root types and which operands exist is a matter of library facilities, and outside the scope of this document to describe.

Visual Prolog 7.3 Language Reference

Page 65 / 147

Constants
Constants Sections
A constants section defines a set of constants in the current scope. ConstantsSection : constants ConstantDefinition-dot-term-list-opt

Constant Definitions
A constant definition defines a named constant, its type, and its value. ConstantDefinition: one of ConstantName = ConstantValue ConstantName : TypeName = ConstantValue

ConstantName: LowerCaseIdentifier The ConstantValue should be an expression, which can be evaluated at compile time and it should have the type of the correspondent domain. The ConstantName should be a lower case identifier. The TypeName can be omitted only for the following built-in domains: 1. Numerical (i.e. integral or real) constants. In this case, the corresponding anonymous numerical domain is adopted for a constant (see the numerical domains for details). 2. Binary constants. 3. String constants. 4. Character constants. Example constants my_char = 'a'. true_const : boolean = true. binaryFileName = "mybin". myBinary = #bininclude(binaryFileName).

Visual Prolog 7.3 Language Reference

Page 66 / 147

Predicates
Predicates Sections
A predicates section declares a set of object or class predicates in the current scope. PredicatesSection : class-opt predicates PredicateDeclaration-dot-term-list-opt The keyword class can be used only inside class implementations, as predicates, declared in an interface, are always object predicates and predicates, declared in a class declaration, are always class predicates already. The keyword class can be used only inside class implementations, since:
n n

predicates declared in an interface are always object predicates and predicates declared in a class declaration are always class predicates.

Predicate Declarations
The predicate declaration is used to declare the predicate in scopes in which the predicate declaration can be seen. When predicates are declared in an interface definition, this means that objects of the corresponding type must support these predicates. When predicates are declared in a class declaration, this means that the class publicly provides the declared predicates. And if predicates are declared in a class implementation, this means that the predicates are available locally. In all cases a corresponding definitions of the predicates must exist. PredicateDeclaration : PredicateName : PredicateDomain LinkName-opt PredicateName : PredicateDomainName LinkName-opt

LinkName : as StringLiteral

PredicateName : LowerCaseIdentifier Here predicateDomainName is the name of a predicate domain declared in the domains section. A predicate declaration states the name of the predicate, its type, mode, flow (see predicate domains), and optionally a link name. Only class predicates can have link names. If the link name is not stated then a link name is derived from the predicate name, the way this name is derived depends on the calling convention. If the calling convention is apicall then the link name stated in the as clause is decorated anyway. If this decoration is unintended, use stdcall instead. Decorated Sometimes a name must have the _...@N decoration, but the default from apicall is wrong. In such cases decorated, decoratedA and decoratedW can be used to control the decoration:

Visual Prolog 7.3 Language Reference

Page 67 / 147

predicates myPredicate : (string X) language stdcall as decorated. In this case the link name will be "_MyPredicate@4", where apicall would make it "_MyPredicateW@4".

predicates myPredicate : (pointer X) language stdcall as decoratedA. In this case the link name will be "_MyPredicateA@4", where apicall would make it "_MyPredicate@4".

predicates myPredicate : (pointer X) language stdcall as decoratedW. In this case the link name will be "_MyPredicateW@4", where apicall would make it "_MyPredicate@4". All of them change the start of the name from xxxx to _Xxxx and all of them put @N behind. The first never uses a suffix; the second always uses A and the third always uses W. This means that the programmer is responsible for deciding which suffix is needed. But he needs not to worry about calculating argument size and initial "_X".

Constructors Sections
A constructors section declares a set of constructors. The constructors belong to the scope in which the constructors section occurs (see class declaration and class implementation). ConstructorsSection : constructors ConstructorDeclaration-dot-term-list-opt Constructor sections can only occur in declarations and implementations of classes that construct objects.

Constructor Declarations
A constructor declaration declares a named constructor of a class. A constructor actually has two associated predicates:
n n

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

An associated constructor object predicate is used to perform an object initialization. This predicate can only be called from the constructor in the class itself and from a constructor in a class that inherits from the class (i.e. base class initialization). ConstructorDeclaration : ConstructorName : PredicateDomain It is illegal to state a predicate mode for constructors, constructors always have procedure mode. Example Consider the following class:
Visual Prolog 7.3 Language Reference Page 68 / 147

class test_class : test constructors new : (integer Argument). end class test_class The associated class level predicate has the following signature: class predicates new : (integer) -> test. Whereas the associated object level predicate has the following signature: predicates new : (integer). Also consider the following implementation: implement test2_class inherits test_class clauses new() :test_class::new(7), % invoke the base class constructor on "This" p(test_class::new(8)). % create a new object of the base class and pass it to p(...) ...

The first call to test_class::new does not return a value, therefore it is a call to the non-function object version of the constructor. I.e. it is an invocation of the base class constructor on "This". The second call on the other hand does return a value, therefore it is a call to the class function version of the constructor. I.e. we are creating a new object.

Predicates from Interface


An interface can support a subset of another interface by stating the predicates in a predicates from section. The predicates from section names the interface and all supported predicates. The predicates are stated by name or by name and arity. If an interface supports a subset of another interface it is neither subtype or super-type related to the other interface. The important thing about the predicates from section is that the mentioned predicates retain their origin interface. Therefore:
n n

there will be no support conflict with any predicates from the origin interface; they can be inherited as the predicates from the origin interface. PredicatesFromInterface : predicates from InterfaceName PredicateNameWithArity-comma-sep-list-opt

PredicatesFromInterface can only be used in interface definitions. Example

Visual Prolog 7.3 Language Reference

Page 69 / 147

interface aaa predicates ppp : (). qqq : (). end interface aaa interface bbb predicates from aaa ppp predicates rrr : (). end interface bbb interface ccc supports aaa, bbb end interface c c c Even though aaa and bbb both declare a predicate ppp, ccc can support them both without any conflicts, because ppp has aaa as an origin interface in all cases. Example interface aaa predicates ppp : (). qqq : (). end interface aaa interface bbb predicates from aaa ppp predicates rrr : (). end interface bbb class aaa_class : aaa end class aaa_class class bbb_class : bbb end class bbb_class implement aaa_class inherits bbb_class clauses qqq(). end implement aaa_class aaa_class can inherit ppp from bbb_class, because ppp in both classes has aaa as origin interface.

Arity
A predicate that takes N arguments are said to be N-ary, or to have arity N. Predicates with different arity are always different predicates, even if they have the same name. In most situations the arity of a predicate is obvious from the context in which the predicate is mentioned. But in, for example, predicatesFromInterface sections and resolve qualifications the arity is not obvious. In order to distinguish between different arities of predicates in predicates from sections and in resolve qualifications, predicate names can (optionally) be stated with arity. The following arities are possible:
n n

Name/N meaning an ordinary predicate (i.e. not a function) Name of arity N. Name/N-> meaning a function Name of arity N.
Page 70 / 147

Visual Prolog 7.3 Language Reference

Name/N... meaning an ordinary predicate Name with N arguments followed by an Ellipsis argument (i.e. a varying number of arguments). (Ellipsis "..." can be used in predicate and predicate domain declarations as the last formal argument. In this case it means that the declared predicate (predicate domain) can have a variable number of arguments. Ellipsis flow must match an ellipsis argument and can therefore be only the last flow in the flow pattern.) Name/N...-> meaning a function Name with N arguments followed by an ellipsis argument. PredicateNameWithArity : PredicateName Arity-opt

Arity : one of / IntegerLiteral Ellipsis-opt / IntegerLiteral Ellipsis-opt -> In Name/0... and Name/0...->. the zero is optional and can thus be written as Name/... and Name/...->, respectively.

Visual Prolog 7.3 Language Reference

Page 71 / 147

Properties
The properties section declares a set of object or class properties in the current scope.

Properties sections
A properties section declares a set of object or class properties in the current scope. PropertiesSection : class-opt properties PropertyDeclaration-dot-term-list-opt The keyword class can be used only inside class implementations, since:
n n

properties declared in an interface are always object properties and properties declared in a class declaration are always class properties.

Peoperty Declaration
PropertyDeclaration : PropertyName : PropertyType FlowPattern-list-opt

FlowPattern: one of (i) (o) The properties are declared similar to single facts. If flow patterns are skipped, both (i) and (o) are assumed. For example: interface ip properties duration : integer. initialized : boolean. scale : string. end interface The properties are used exactly like single facts inside the implementation. It is possible to qualify properties for a scope name or object. X is an object that supports the interface ip X:duration := 5, if X:initialized = true then ... else ... end if, X:scale := "meter", .... Inside an implementation of ip you access the properties as if they were facts. duration := 5, if initialized = true then ... else ... end if, scale := "meter", ....

Visual Prolog 7.3 Language Reference

Page 72 / 147

Implementation
You implement a property by defining a function for getting the value and an appropriate predicate to set it. E.g., clauses duration() = duration_fact * scale. duration(D):- duration_fact := D/ scale. Or as a fact with the same name as the property facts initialized : boolean := false. You cannot have set and get predicates and a fact with the same name. So if you want a fact, which stores the value of the property, which often is the case, you will have to give this fact another name e.g.: properties duration : integer. facts duration_fact : integer. clauses duration() = duration_fact. clauses duration(D) :OldDuration = duration_fact, duration_fact := D, OldDuration < D, > !, sendChanged(). duration(_D). You cannot use the duration predicates as predicates (not surprisingly they are not declared as predicates, but as a property; it is just the way the get- and set-methods of the property are implemented). But in the predicate names are taken - so you cannot declare a predicate duration\1 or duration\0->. Implementation Detail When you access a property declared in an interface, you cannot make any assumptions about how it is implemented; so you have to assume that it is implemented with predicates. So if the programmer has defined the property as a fact, the compiler will have to generate the proper predicates. And use them, when accessing the property through an interface. Inside the implementation, a property defined as a fact can be accessed simply as a fact.

Read or Write Restrictions


Sometimes you want to have a property, which can only be read or written to. Assume we declare them with an i/o pattern as:

Visual Prolog 7.3 Language Reference

Page 73 / 147

duration duration duration duration

: : : :

integer (o). % a read only property integer (i). % a write only property integer (o) (i). % a normal property, which can be both written to and read from. This is equivalent integer. % equivalent to the declaration above.

If a property is declared as a read-only property, you only need to declare the get predicate and likewise if it is declared as write-only only the set predicate. Of course if you implement the property as a fact then the fact can be used as a normal fact inside the implementation.

Properties from Interface


An interface can support a subset of another interface by stating the properties in a properties from section. The properties from section names the interface and all supported properties. If an interface supports a subset of another interface it is neither subtype or super-type related to the other interface. The important thing about the properties from section is that the mentioned properties retain their origin interface. Therefore:
n n

there will be no support conflict with any properties from the origin interface; they can be inherited as the properties from the origin interface. PropertiesFromInterface : properties from InterfaceName PpropertyName-comma-sep-list-opt

PropertiesFromInterface can only be used in interface definitions. Example interface aaa properties pp : integer. qq : boolean. end interface aaa interface bbb properties from aaa pp properties rr : string. end interface bbb interface ccc supports aaa, bbb end interface c c c Even though aaa and bbb both declare a property pp, ccc can support them both without any conflicts, because pp has aaa as an origin interface in all cases. Example interface aaa properties pp : integer. qq : boolean. end interface aaa

Visual Prolog 7.3 Language Reference

Page 74 / 147

interface bbb properties from aaa pp properties rr : string. end interface bbb class aaa_class : aaa end class aaa_class class bbb_class : bbb end class bbb_class implement aaa_class inherits bbb_class facts pp_fact(): integer. clauses pp()= pp_fact-3. clauses pp(D):- pp_fact:=D+3. end implement aaa_class aaa_class can inherit pp from bbb_class, because pp in both classes has aaa as origin interface.

Visual Prolog 7.3 Language Reference

Page 75 / 147

Facts
A facts section declares a fact database, consisting of a number of facts. The fact database and the facts belong to the current scope. Fact databases can exist on a class level as well as on an object level. Facts sections can be declared only in class implementations. If the fact database is named, an additional compound domain is implicitly defined. This domain has the same name as the fact section and has functors corresponding to the facts in the fact section. If the facts section is named, the name denotes a value of the build-in domain factDB. The save and consult predicates accept values of this domain. FactsSection : class-opt facts FactsSectionName-opt FactDeclaration-dot-term-list-opt

FactsSectionName : - LowerCaseIdentifier

Fact Declarations
A fact declaration declares a fact of a fact database. A fact declaration is either a fact variable, or a functor fact. FactDeclaration : FactVariableDeclaration FactFunctorDeclaration

FactFunctorDeclaration : FactName : ( Argument-comma-sep-list-opt ) FfactMode-opt

FactName : LowerCaseIdentifier A fact functor declaration has nondeterm fact mode by default. A fact functor can have initialization via clauses section. In such case values in the clauses should be expressions, which can be evaluated at compile time. FactMode : one of determ nondeterm single If mode is single, then a fact always has one and only one value and the assert predicate overwrites old value with a new one. Predicate retract cannot be applied to single facts. If mode is nondeterm, then the fact can have zero, one, or any other number of values. If mode is determ, then the fact can have zero or one value. If fact has zero values, then any read access to it gives fail.

Fact Variable Declarations

Visual Prolog 7.3 Language Reference

Page 76 / 147

A fact variable is similar to a one-argument single functor fact. However, syntactically it is used as a mutable variable (i.e. with assignment). FactVariableDeclaration : FactVariableName : Domain InitialValue-opt

InitialValue : := ConstantValue := erroneous

FactVariableName : LowerCaseIdentifier A constant value ConstantValue should be a term (of the Domain type), which can be evaluated at compile time. The constant value can be omitted only if the fact variable is initialized in a constructor. Class fact variables should always have an initial constant value. Notice that the keyword erroneous can be used as value to be assigned to fact variables. That is both lines below are valid: facts thisWin : vpiDomains::windowHandle := erroneous. clauses p() :- thisWin := erroneous. The idea of assigning erroneous value is to give clear runtime error if some code uses uninitialized fact variable by mistake.

Facts
Facts can only be declared in a class implementation and subsequently they can only be referenced from this implementation. So the scope of facts is the implementation in which they are declared. But the lifetime of object facts is the lifetime of the object to which they belong. Likewise the lifetime of class facts are from program start to program termination. Example The following class declares an object fact objectFact and a class fact classFact: implement aaa_class facts objectFact : (integer Value) determ. class facts classFact : (integer Value) determ. ... end implement aaa_class

Visual Prolog 7.3 Language Reference

Page 77 / 147

Clauses
Clauses Section
A clauses section consists of a set of clauses. The clauses section contains implementations of predicates or initial values of facts. A single clause section can have clauses for several predicates and facts. On the other hand, all clauses for one predicate/fact (the same name and arity) must be grouped together in one clauses section and without intervening clauses of other predicates/facts. ClausesSection : clauses Clause-dot-term-list-opt See also Guards in Monitors.

Clauses
Clauses are used to define predicates. A single predicate is defined by a set of clauses. Each clause is executed in turn until one of them succeeds, or there is no more clauses left to execute. If no clause succeeds the predicate fails. If a clause succeeds and there are more relevant clauses in a predicate left, the program control can later backtrack to the clauses of this predicate to search for other solutions. Thus, a predicate can fail, succeed, and even succeed multiple times. Each clause has a head and optionally a body. When a predicate is called the clauses are tried in turn (from top to bottom). For each clause the head is unified with the arguments from the call. If this unification succeeds then the body of the clause (if such one exist) is executed. The clause succeeds if the match of the head succeeds and the body succeeds. Otherwise it fails. A clause consists of a head and an optional body. Clause : ClauseHead ReturnValue-opt ClauseBody-opt .

ClauseHead : LowercaseIdentifier ( Term-comma-sep-list-opt )

ReturnValue : = Term

ClauseBody : :- Term See also Guards in Monitors.

Goal Section
The goal section is the entry to a program. When the program starts it executes the goal, when the

Visual Prolog 7.3 Language Reference

Page 78 / 147

goal is executed, the program exits. GoalSection : goal Term. The goal section consists of a clause body. The goal section defines its own scope, therefore all invocations should contain class qualifications. Normally, the goal must have procedure mode.

Visual Prolog 7.3 Language Reference

Page 79 / 147

Terms
This section describes terms and how execution/evaluation of terms and clauses proceeds. Semantically, there are two kinds of terms: formulas and expressions.
n n

Expressions represent values, like the number 7. Formulas represent logical statements, like "the number 7 is greater than the number 3".

Syntactically the two kinds have a huge overlap and therefore the syntax unites the two kinds into terms. The following definition of Term is simplified, in the sense that it includes syntactic constructions that are not legal. For example, one cannot legally write ! + !. We do however believe that using this simple syntax description in combination with intuitive understanding of language concepts, the type system, and the operator hierarchy described below is better for most purposes. Term: ( Term ) Literal Variable Identifier MemberAccess PredicateCall PredicateExpression UnaryOperator Term Term Operator Term Cut Ellipsis FactvariableAssignment

Backtracking
The evaluation of a Prolog program is a search for a "solution" to the goal. Each step in the search for a solution can either succeed or fail. At certain points in the program execution there are more than one possible choices for finding a solution. When such a choice point is met a so called backtrack point is created. A backtrack point is a recording of the program state plus a pointer to the choice that was not executed. If it turn out that the original choice could not provide the solution (i.e. if it fails), then the program will backtrack to the recorded backtrack point. Thereby restoring the program state and pursuing the other choice. The mechanism will be described and exemplified in details in the following sections.

Literals
Literals have universal type. Literal: IntegerLiteral RealLiteral CharacterLiteral StringLiteral BinaryLiteral ListLiteral CompoundDomainLiteral See also Literals (in Lexical Elements)

Variables
Variables in Visual Prolog are immutable: once they are bound to a value they retain that value, but
Visual Prolog 7.3 Language Reference Page 80 / 147

backtracking can unbind the variable again during the process of restoring a previous program state. A variable can thus be bound (during unification and matching), if it is already bound then it evaluates to the value that it is bound to. Variables are names starting with an upper-case letter or with an underscore (_), followed by a sequence of letters (both uppercase and lowercase), digits, and underscore characters (all in all called an UppercaseIdentifier): Variable: UppercaseIdentifer The following are examples of valid variable names: My_first_correct_variable_name _ _Sales_10_11_86 while the next two are invalid: 1stattempt second_attempt The variable consisting of single underscore character (i.e. _) is known as the anonymous variable. The anonymous variable is used in patterns and bindings where the corresponding value is of no interest and should be ignored. Every occurrence of the anonymous variable is an independent anonymous variable, i.e. even though the anonymous variable is used several times in a single clause they have no relation to each other. If variables that starts with an underscore are not anonymous, but they are still intended for values of no interest that should be ignored. The compiler will issue a warning if the value of such a warning is actually not ignored. Prolog variables are local to the clause in which it occurs. That is, if two clauses each contain a variable called X, these X-s are two distinct variables. A variable is said to be free when it is not yet associated with a term and to be bound or instantiated when it is unified with a term. The Visual Prolog compiler does not make a distinction between upper and lower case letters in names, except for the first letter. This means that the two variables SourceCode and SOURCECODE are the same.

Identifier
Identifier: MemberName GlobalScopeMembername ScopeQualifiedMemberName MemberName: LowerCaseIdentifier Identifiers are used to refer to named entities (i.e. classes, interfaces, constants, domains, predicates, facts, ...).

Visual Prolog 7.3 Language Reference

Page 81 / 147

An identifier can just be a lower case identifier (i.e. a lowercase letter followed by a sequence of letters, numbers and underscore characters). Many entities can have the same name. So it may be necessary or desirable to qualify the lowercase identifier the name of the particular scope of interest, or to state that the name is in the global namespace. Example These are examples of unqualified identifiers: integer mainExe myPredicate Global Entities Access The only global entities, which exist in Visual Prolog, are built-in domains, predicates, and constants. Global names are directly accessible in any scope. There might however exist situations where a global name is shadowed by a local or imported name. In that case the global entity can be qualified with a double colon '::' (without a prefixed class/interface name). The double colon can be used everywhere, but the most important place is where an interface name is used as formal parameter type specifier. GlobalScopeMemberName: :: MemberName Example The built-in domain integer is defined in the global scope, to avoid ambiguity or stress that it is this particular domains you can use the global scope member name: ::integer Class/Interface Member Access Static members of classes and interfaces are accessed by means of qualification with the class name (and optionally a namespace prefix): ScopeQualifiedMemberName NamespacePrefix-opt ScopeName :: MemberName NamespacePrefix: NamespaceIdentifier-opt \ ScopeName: LowercaseIdentifier The ScopeName is the name of the class or interface that defines/declares the name. Namespace prefixing is explained in: Referencing names in namespaces. Some names can be accessed without qualification, see scoping & visibility.

Predicate Call
A predicate call have the form PredicateCall: Term ( Term-comma-sep-list-opt )
Visual Prolog 7.3 Language Reference Page 82 / 147

The first term must be an expression that evaluates to a value with predicate type. Typically, it is either the name of a predicate in a class, or an expression that evaluates to a predicate member of an object. Notice that some predicates return values, whereas other predicates do not. A predicate that returns a value is an expression, and the predicate call is often referred to as a function call. A predicate that does return a value is a formula. A predicate is invoked by applying arguments to the predicate. The predicate must have a flowpattern that matches the free/bound state of the arguments. Most predicates are defined by a set of clauses, but some predicates are built into the language and some are defined externally in a DLL (perhaps in a foreign programming language). When a predicate is invoked by a predicate call, each clause is executed in turn until one of them succeeds, or there are no more clauses left to execute. If no clause succeeds the predicate fails. If a clause succeeds and there are more relevant clauses left, a backtrackpoint is created to the next relevant clause. Thus, a predicate can fail, succeed, and even succeed multiple times. Each clause has a head and optionally a body. When a predicate is called the clauses are tried in turn (from top to bottom). For each clause the arguments in the head is unified with the arguments from the call. If this unification succeeds then the body of the clause (if present) is executed. The clause succeeds, if the match of the head succeeds and the body succeeds. Otherwise it fails. Example clauses ppp() :- qqq(X), write(X), fail. qqq(1). qqq(2). qqq(3). When ppp is called it in turn calls qqq. When qqq is called, it first creates a backtrack point pointing to the second clause. Then the first clause is executed. Hereby the free variable X from ppp is matched against the number 1, whereby X is bound to 1. In ppp X (i.e. 1) is written and then fail cause backtracking to the backtrackpoint. Hereby program control is set to the second clause in qqq and the program state is set back to the state it was in when qqq was first entered, i.e. X in ppp is unbound again. Before the actual execution of the second clause in qqq begins a backtrack point to the third clause is created. The execution then proceeds as it did for 1

Unification
When a predicate is called the arguments from the call is unified with the terms in the head of each clause. Unification is the process of binding variables in such a way that two terms become equal, making as few bindings as possible (i.e. leaving as much as possible open for further binding). Variables can be bound to any kind of terms, including variables or terms containing variables.
Visual Prolog 7.3 Language Reference Page 83 / 147

Unification is either possible or impossible, i.e. it can succeed or fail. Variables and terms to which they are unified have types, a variable can only be bound to a term of the same type as the variable, or a subtype. When two variables are bound to each other they must therefore have exactly the same type. Unification takes place (as mentioned) between a predicate call and the clause head. It also takes place when two terms are compared for equality. Example Consider two terms (of the same type): T1 = f1(g(), X, 17, Y, 17) T2 = f1(Z, Z, V, U, 43) We will attempt to unify these two terms from left to right (i.e. a left-to-right pre-traversal). Both T1 and T2 are f1/5 terms, this match. Therefore we attempt to unify each of the arguments from T1 with each correspondent argument of T2. First we must unify Z and g(), this can be unified if we bind Z to g(). So far everything is fine and we have the first binding in our unifier: Z = g() The next two arguments are X and Z, which already has been bound to g(). These two arguments can also be unified if we also bind X to g(). So we now have the following contributions to our unifier: X = Z = g() Next we must bind V to 17 and then we must bind Y to U. So far everything unifies with the following unifier: X = Z = g() V = 17 Y =U The two unified terms are now equivalent to these terms: T1 = f1(g(), g(), 17, Y, 17) T2 = f1(g(), g(), 17, Y, 43) But we have not yet unified the two last arguments, which are 17 and 43. No variable binding can make these terms equal, so all in all the unification fails. T1 and T2 cannot be unified. In the example above T1 could have been a predicate call and T2 a clause head. But they could also have been two terms that were compared with equal "=".

Matching
Matching is the same as unification except that variables can only be bound to grounded terms. A grounded term is a term that does not contain any unbound variables.

Visual Prolog 7.3 Language Reference

Page 84 / 147

It is the flow-patterns that are stated for predicates, that make it possible to use matching rather than full-blown unification. Example clauses ppp(Z, Z, 17). qqq() :ppp(g(), X, 17). Unification of the ppp-call with the ppp-clause is possible with the following unifier: Z = X = g() If ppp have the flow (i,o,i) then the unification is just a match:
n n

g() is input as the first argument, this is bound to Z The second argument in the clause is therefore bound and can thus be output to X, which therefore becomes bound to g(). finally the third argument is 17 used as input this number is simply compared to the third argument in the clause.

It is the flow-pattern that makes it possible to predict that the clause does not need real unification.

Nested Function Calls


Terms that have to be unified or matched with each other are allowed to contain sub-terms that are actually expressions or function calls that have to be evaluated before the unification/matching can be completed. The evaluation of such sub-terms is done on a by-need basis. In a predicate call all input arguments are evaluated before the predicate is called, all output arguments are variables, which does not need evaluation. Clause heads can also contain terms that have to be evaluated, before matching/unification can be determined.
n

n n n

all matching/unification that does not require any evaluation is performed before any evaluation is performed; then evaluation corresponding to input arguments is performed one by one left-to-right. Comparing each value to the corresponding input after each evaluation; then the clause body is evaluated; then the output arguments are evaluated (left-to-right); then the return value (if the predicate is a function) is evaluated.

If any of these fail then the rest of the evaluation is not carried out. All in all the base principles are:
n n n

input after other match, before body evaluation output after body evaluation left-to-right

Anonymous Predicates
An anonymous predicate is an expression that evaluates to a predicate value. The predicate value

Visual Prolog 7.3 Language Reference

Page 85 / 147

can be bound to a variable, passed as arguments or returned as result, but the value does not have a name in any class, interface or implementation. Anonymous predicates have the ability to capture values from the context in which the expression occurs, this is a rather powerful ability that can be used to avoid rather excessive amount of strange/unpleasant code. Syntax Anonymous predicates are terms: Term : one of ... AnonymousPredicate ... An anonymous predicate is a nameless clause in curly brackets. Certain parts are optional, giving these forms: AnonymousPredicate : one of { ( Arg-comma-sep-list ) = Term } { ( Arg-comma-sep-list ) = Term :- Term } { ( Arg-comma-sep-list ) :- Term } { = Term } { = Term :- Term } { :- Term } Leaving out the argument list means "the required number of arguments" and can be used whenever the arguments are not used. Semantics An anonymous predicate expression evaluates to a predicate value. Consider this code: clauses run() :Inc = { (X) = X+1 }, A = Inc(4), B = Inc(23), stdio::writef("A=%,B=%", A, B). Inc becomes an increment predicate, so the program will write: A = 5, B = 24 The code in this example corresponds to this code: clauses run() :Inc = inc, A = Inc(4), B = Inc(23), stdio::writef("A=%,B=%", A, B). class predicates inc : (integer X) -> integer R. clauses inc(X) = X+1.
Visual Prolog 7.3 Language Reference Page 86 / 147

Where the clause (X) = X+1 can be found in the last line. I.e. this time in a named predicate. Variables that are bound outside (i.e. before the occurrence of) an anonymous predicate can be used inside the anonymous predicate. The value of variable will be captured by the anonymous predicate. Variables that are bound in an anonymous predicate are local variables in the anonymous predicate. Capturing context An anonymous predicate can capture context, which means that it can refer to things that are defined in its context, especially facts and variables from the clause. Capturing Variables Anonymous predicate occurs in a clause, and this clause may contain variables. Those variables that are bound before the anonymous predicate is met can be used inside the anonymous predicate. This code illustrates how a variable is captured: domains pred = (integer) -> integer. class predicates createAdder : (integer A) -> pred Adder. clauses createAdder(A) = { (X) = X+A }. clauses run() :Add17 = createAdder(17), A = Add17(4), B = Add17(20), stdio::writef("A=%,B=%", A, B). We call createAdder with 17 as argument. So in the createAdder clause A is 17, and therefore the result is { (X) = X+17 }. We say that the anonymous predicate has captured the variable A. Since Add17 is a predicate that adds 17 to its argument, the output of the code will be: A = 21, B = 37

Capturing ellipsis (...) An anonymous predicate can capture the ellipsis variable (i.e. ...): clauses ppp(...) :W = { () :- stdio::write(...) }, qqq(W). W captures the ellipsis variable. qqq receives a zero-arity predicate, when this predicate is invoked the captured ellipsis variable will be written to the standard output device. Capturing Facts An anonymous predicate can access facts. If it is created by a class predicate it can access class facts. If it is created by an object predicate it can access both object and class facts. Consider this

Visual Prolog 7.3 Language Reference

Page 87 / 147

code that captures a class fact: class facts count : integer := 0. clauses seq() = { () = count :- count := count+1 }. clauses run() :A = seq(), B = seq(), stdio::writef("A1=%,", A()), stdio::writef("B1=%,", B()), stdio::writef("A2=%,", A()), stdio::writef("B2=%", B()). Both A and B increment the class fact count, so the result is A1 = 1, B1 = 2, A2 = 3, B2 = 4 In object predicates we can capture object facts. So assuming that seq is an object predicate in myClass, this code illustrates the capture of an object fact: facts count : integer := 0. clauses seq() = { () = count :- count := count+1 }. clauses run() :A = myClass::new():seq(), B = myClass::new():seq(), stdio::writef("A1=%,", A()), stdio::writef("B1=%,", B()), stdio::writef("A2=%,", A()), stdio::writef("B2=%", B()). In this case A and B comes from two different objects, which each have a count fact, so the output will be: A1 = 1, B1 = 1, A2 = 2, B2 = 2 Technically, the class version actually doesn't capture anything, it merely have access to the fact. Likewise, the object version doesn't actually capture the fact, instead it captures This and through This it obtains access to the object facts. Capturing This As described above it is possible to capture This and thereby gaining access to objects facts. The same mechanism gives access to calling object predicates. clauses seq() = { () = count :- inc() }. clauses inc() :- count := count+1. This can also be used directly:

Visual Prolog 7.3 Language Reference

Page 88 / 147

clauses ppp() = { () = aaa::rrr(This) }. Nesting Anonymous predicates can be nested: clauses run() :P = { (A) = { (B) = A+B } }, Q = P(3300), R = P(2200), stdio::writef("Q(11)=%,", Q(11)), stdio::writef("R(11)=%", R(11)). To obtain Q we call P with 3300, so A is 3300 and Q therefore becomes { (B) = 3300+B } }, likewise R becomes { (B) = 2200+B } }. So, the output is: Q(11) = 3311, R(11) = 2211

Syntactic Sugar If you don't need the arguments they can be skipped. So this code-fragment: P = { (_) :- succeed }, Q = { (_, _) = 0 }, R = { (_, _, _) = _ :- fail } Can be shortened down to this: P = { :- succeed }, Q = { = 0 }, R = { = _ :- fail } Notice that the arguments are completely skipped. If you write () it means zero arguments, whereas skipping the arguments means "a suitable amount" of arguments. Examples of practical usage This section shows some cases where anonymous predicates are very handy. The examples assume that the PFC scopes core, std, stdio, list and string are open. Dummy predicates Anonymous predicates are good for creating dummy predicate values: ppp( { = true } ), % don't filter (boolean) qqq( { :- succeed } ), % don't filter (determ) rrr( { = 17 } ), % all rows must have height 17 Adaptation In cases where you need a predicate and have one that is almost suitable, you can make the adaptation using an anonymous predicate. Index adaptation

Visual Prolog 7.3 Language Reference

Page 89 / 147

Consider the predicate write3: class predicates write3 : (function{integer, string} Indexer). clauses write3(Indexer) :foreach I = std::fromTo(0,2) do write(Indexer(I), "\n") end foreach. Indexer implements an "array" of strings, write3 will write the three strings found at the indexes , 1 and 2. So write3 assumes that the "array" index is zero-based. However, the "array" we have uses a one-based index: class predicates myArray : (integer N) -> string Value. clauses myArray(1) = "First" :- !. myArray(2) = "Second" :- !. myArray(3) = "Third" :- !. myArray(_) = _ :raiseError(). But using an anonymous predicate we can easily adapt the one-based array to the zero-based usage: % myArray is 0-based, write3 requires 1-based Arr = { (N) = myArray(N+1) }, write3(Arr) So we get the expected output: First Second Third Parameter adaptation In this code listChildren will call a ChildWriter predicate for each "C is the child of P"-pair: class predicates listChildren : (predicate{string,string} ChildWriter). clauses listChildren(CW) :CW("Son1", "Father"), CW("Son2", "Father"). We will however prefer to list the "P is the parent of C" using the predicate wParent: class predicates wParent : (string Parent, string Child). clauses wParent(P, C) :writef("%istheparentof%\n", P, C). wParent takes the arguments in the opposite order, but we can easily adapt using an anonymous
Visual Prolog 7.3 Language Reference Page 90 / 147

predicate: Swap = { (A,B) :- wParent(B,A) }, listChildren(Swap) And then the out becomes the expected: Father is the parent of Son1 Father is the parent of Son2 We can also throw away arguments, for example when calling this predicate that only needs a Child: class predicates wKnowParent : (string Child). clauses wKnowParent(C) :writef("Weknowaparentof%\n", C). The adaptation looks like this: Fewer = { (C,P) :- wKnowParent(C) }, listChildren(Fewer) The output will be: We know a parent of Son1 We know a parent of Son2 We can also supply dummy arguments: More = { (_,P) :- addChildren(P, 1) } listChildren(More) Here addChildren will "add a count of children to P". Since each invocation corresponds to one child we will call addChild supplying 1 as a "dummy" argument. The More is thus an adaptor that both throws away an argument and supplies a dummy argument. Filters Assume this predicate: class predicates writeFiltered : (string L, filterPredicate{integer} Filter). clauses writeFiltered(Label, Filter) :List = [1,2,3,4,5,6,7,8,9], FilteredList = filter(List, Filter), writef("%\t%\n", Label, FilteredList). Filter is used to filter the list [1,2,3,4,5,6,7,8,9]; the filtered list and the Label are written to the standard output.

Visual Prolog 7.3 Language Reference

Page 91 / 147

First we use the allow-all filter: All = { :- succeed }, writeFiltered("All", All) This filter simply succeeds for any element, so the output is the entire list: All [1,2,3,4,5,6,7,8,9]

It is just as easy to create a filter that fails for all elements and thus allow-none: None = { :- fail }, writeFiltered("None", None) The output from this is the empty list: None []

We can also create filters for elements greater than 3 and elements dividable by 3: GreaterThan3 = { (X) :- X > 3 }, writeFiltered("> 3", GreaterThan3), Rem3 = { (X) :- 0 = X rem 3 }, writeFiltered("Rem3", Rem3) The output from this is: >3 [4,5,6,7,8,9] Rem3 [3,6,9]

Sorting The list package has a sort predicate. But sometimes the default order is not what you need. Therefore the list package also has a predicate sortBy, which sorts the elements using a programmer defined compare operation. Let us first consider string sorting, using this predicate: class predicates writeStringsSorted : (string Label, comparator{string} Comp). clauses writeStringsSorted(Label, C) :List = ["John Wayne", "Uma Thurman", "Harrison Ford", "Nicolas Cage", "Elizabeth Taylor", "Cary Grant", "Jerry Lewis", "Robert De Niro"], Sorted = sortBy(C, List), write(Label, "\n"), foreach S = list::getMember_nd(Sorted) do writef("%\n", S) end foreach. We can call the predicate with the "normal" comparator, and using an anonymous predicate we can easily sort it descending as well:

Visual Prolog 7.3 Language Reference

Page 92 / 147

Normal = compare, writeStringsSorted("Normal", Normal), Descending = { (A,B) = compare(B,A) }, writeStringsSorted("Descending", Descending) The output looks like this: Normal Cary Grant Elizabeth Taylor Harrison Ford Jerry Lewis John Wayne Nicolas Cage Robert De Niro Uma Thurman Descending Uma Thurman Robert De Niro Nicolas Cage John Wayne Jerry Lewis Harrison Ford Elizabeth Taylor Cary Grant Let us also sort some more complex elements. Here a person has a first name and a last name, using this domain: domains person = p(string First, string Last). For the demonstration we will use this test predicate: class predicates writePersonsSorted : (string Label, comparator{person} Comparator). clauses writePersonsSorted(Label, C) :List = [p("John","Wayne"), p("Uma","Thurman"), p("Harrison","Ford"), p("Nicolas","Cage"), p("Elizabeth","Taylor"), p("Cary","Grant"), p("Jerry","Lewis"), p("Robert","De Niro")], Sorted = sortBy(C, List), write(Label, "\n"), foreach p(F,L) = list::getMember_nd(Sorted) do writef("%%\n", F, L) end foreach. Again we can sort using the normal and a descending comparator: Normal = compare, writePersonsSorted("Normal", Normal), Descending = { (A,B) = compare(B,A) }, writePersonsSorted("Descending", Descending)

Visual Prolog 7.3 Language Reference

Page 93 / 147

Since the compare predicate uses left-to-right lexicographic order on the p-functor, the result is the same as before: Normal Cary Grant Elizabeth Taylor Harrison Ford Jerry Lewis John Wayne Nicolas Cage Robert De Niro Uma Thurman Descending Uma Thurman Robert De Niro Nicolas Cage John Wayne Jerry Lewis Harrison Ford Elizabeth Taylor Cary Grant But with the more complex domain we can create a comparator that will sort on last name: LN = { (p(_,L1), p(_, L2)) = compare(L1,L2) }, writePersonsSorted("LastName", LN) The result is what we expect: LastName Nicolas Cage Robert De Niro Harrison Ford Cary Grant Jerry Lewis Elizabeth Taylor Uma Thurman John Wayne Capturing context As mentioned a very powerful feature of anonymous predicates is the ability to capture context. The examples in this section show some ways you can use this. Background threads The routine for starting a thread takes a null-ary predicate and run it in the new thread. But you nearly always need to pass some input data to the job in the new thread. This is possible in several ways, but the absolutely simplest way is to use anonymous predicates. The project bgDemo from the Visual Prolog example collection (that can be installed from the IDE) use this method. The project has a form that can start background job and display status information from the job in a jobControl that is added to the form. A background job is a predicate that will receive a jobLog, which it can use to report status and completion degree: domains job = (jobLog Log). A jobLog looks like this:

Visual Prolog 7.3 Language Reference

Page 94 / 147

interface jobLog properties completion : real (i). properties status : string (i). end interface jobLog The job can report completion degree by setting the completion property (range to 1). Likewise, the status property can be used to reflect the current status of the job. The status and completion will be shown in the form together with a job name. A job is started by calling the form's addJob predicate: clauses addJob(JobName, Job) :JobCtrl = jobControl::new(This), JobCtrl:name := JobName, JobCtrl:show(), assert(jobCtrl_fact(JobCtrl)), arrange(), JobLog = jobLog::new(JobCtrl), Action = { :- Job(JobLog) }, _ = thread::start(Action). In this context it is the last three lines that are interesting. thread::start takes a null-ary predicate as argument, but a job is a predicate that takes a jobLog as argument. Therefore we create an anonymous predicate Action, which takes no arguments but invokes Job on the JobLog. The anonymous predicate has captured both Job and JobLog from the context, and subsequently both these values are transferred to the new thread even though this thread only receives a null-ary predicate. The jobs in the bgDemo project are merely dummy jobs that only manipulate their jobLog. One of them looks like this: clauses job(Log, From, To) :Log:status := "Step 1", foreach N1 = std::fromTo(From, To) do Log:completion := (N1-From) / (To-From) / 2, programControl::sleep(3) end foreach, Log:status := "Step 2", foreach N2 = std::fromTo(From, To) do Log:completion := (N2-From) / (To-From) / 2 + 0.5, programControl::sleep(3) end foreach, Log:status := "finished". It has two loops which run from From to To and calculates the completion and sets it on the Log. It also sets the status text before, between and after the loops. You may notice that the job does not have the proper job type, because a proper job only has one argument (the jobLog), this job has three arguments. Again it is anonymous predicates that help us. The code that adds the jobs to the form looks like this:

Visual Prolog 7.3 Language Reference

Page 95 / 147

predicates onFileNew : window::menuItemListener. clauses onFileNew(_Source, _MenuTag) :JF = jobForm::display(This), Job11 = {(L) :- job1::job(L, 1, 1000)}, Job12 = {(L) :- job1::job(L, 200, 600)}, Job13 = {(L) :- job1::job(L, 1200, 3000)}, Job14 = {(L) :- job1::job(L, 1, 1000)}, JF:addJob("job1.1", Job11), JF:addJob("job1.2", Job12), JF:addJob("job1.3", Job13), JF:addJob("job1.4", Job14), ... In a more realistic program, it is most likely that From and To would not be constants, but rather parameters passed from some outer place. In that case these anonymous predicates would also capture variables from the context. The jobLog in the bgDemo illustrates one more usage of anonymous predicates. The jobLog pass the completion and the status information to a jobControl. The jobControl is a GUI control on the jobForm capable of doing a suitable rendering of the information. This however gives a synchronization problem, because GUI controls are not thread safe and here we want to update some controls from a background thread. This can lead to conflicts, because it is the main thread that draws the controls. The solution is to make transfer the the update of the control to the GUI thread. We do this by posting actions to the control. The implementation of the status update looks like this: clauses status(Status) :Action = { :- jobCtrl:status := Status }, jobCtrl:postAction(Action). Action is a null-ary predicate that will set the status in the jobCtrl. We post this action to the jobCtrl. When the jobCtrl receives the action it invokes it and is thus updated. This way that actual update of the control will be performed by the GUI thread. This anonymous predicate not only captures the Status variable it also captures the jobCtrl fact. Asynchronous callbacks Assume that we send commands to a remote service. The command execution is asynchronous, so when we execute a command we also give a callback action which will be invoked when the execution of the command is finished. To execute a command we must call this predicate: predicates executeCommand : (command Cmd, predicate{} OnDone). Based on this predicate we want to create a similar predicate that can execute a list of commands. A certain command should be executed when the previous command completes. We will also make our list executor asynchronous, so we supply an action that will be invoked when the entire script of commands are finished. Our script executer will have the form: predicates executeScript : (command* Script, predicate{} OnDone). If the script is empty we simply invoke the OnDone action. If the script has a command H and a rest script T, we must first execute H, and when it is finished we must execute the rest of the script T. So the OnDone action we supply when executing H must execute T. All in all, the implementation can look like this:

Visual Prolog 7.3 Language Reference

Page 96 / 147

clauses executeScript([], OnDone) :OnDone(). executeScript([H|T], OnDone) :DoneH = { :- executeScript(T, OnDone) }, executeCommand(H, DoneH). We have used an anonymous predicate to perform the execution of the rest of the script. This anonymous predicate captures T and OnDone.

Fact Variable Assignment


Assign operator := is used to assign a new value for a fact variable FactVariable. The Term must be evaluated to a value of suitable type (i.e. the same type as the fact variable, or a subtype). FactVariableAssignment: FactVariable := Term

Facts
A fact database contains a number of fully instantiated (grounded) predicate heads corresponding to the facts from the facts section declaration. The facts can be accessed by a predicate call, using the fact name as the predicate name. The predicate call is matched against each fact in turn; succeeding with a possible backtrack point to the next fact each time the predicate call match the fact. When there are no more facts in the fact database then the predicate call fails. New facts can be asserted using the predicates assert/1, asserta/1, and assertz/1. assert/1 is the same as assertz/1 and it asserts a new fact to the end of the list of facts, whereas asserta/1 asserts a new fact to the start of the list. Existing facts can be retracted with the predicate retract/1 and retractAll/1. retract/1 retracts the first fact that match the argument binding variables in the argument and leaving a backtrack point so that more facts will potentially be retracted when backtracking. retractAll/1 retracts all facts that matches the arguments and succeeds without any binding.

Operators
Operators are organized in a precedence hierarchy. In the rule below operators in each group have same precedence, which is higher than those below. I.e. the power operator has higher precedence than unary minus and plus, which in turn has higher precedence than the multiplication operators, etc. Parenthesis can be used to circumvent the precedence (and for clarification). Operator: one of PowerOperator UnaryOperator MultiplicationOperator AdditionOperator RelationOperator MustUnifyOperator AndOperator OrOperator

UnaryOperator: one of - +

Visual Prolog 7.3 Language Reference

Page 97 / 147

All operators except the UnaryOperator's are binary. The power operator is right associative, all other operators are left associative. The RelationOperator and the MustUnifyOperator has same precedence. Notice that the placement UnaryOperator is not consistent with mathematics, where these operators are at the same level as the AdditionalOperator's. The difference has no influence of the calculated value, but it allows writing 2*-2, where mathematics would require a parenthesis around the second operator 2*(-2). It also means that -2*2 is mmeans (-2)*2 where it would be -(2*2) in mathematics (the resulting value is the same). Example -2^2 is the same as -(2^2) because ^ has higher precedence than unary minus. Example 3^2^2 is the same as 3^(2^2) because ^ is right associative. Example -2*-3^-4+5 is the same as ((-2) * (-(3 ^ (-4)))) + 5. Example The following term: 7 + 3 * 5 * 13 + 4 + 3 = X / 6A < 7, p(X) has the same meaning as this term: ((((7 + ((3 * 5) * 13)) + 4) + 3) = (X / 6))((A < 7) , p(X)) I.e. at outermost level the term is an "or" of two terms, the first of these is a relational (=) term, the second is an "and" term, etc. Arithmetic Operators The arithmetic operators are used for arithmetic operations on numbers. They are expressions, which takes expressions as arguments. They have root types as arguments and return universal types as result. (See Universal and Root types.) PowerOperator: ^

MultiplicationOperator: one of * / div mod quot rem

AdditionOperator: one of + Relational Operators The relational operators are formulas, which takes expressions as arguments. Given this nature they are non-associative.

Visual Prolog 7.3 Language Reference

Page 98 / 147

RelationOperator: one of = > < > = < = < >

> <

First the left term is evaluated, then the right term is evaluated and then the results are compared. Notice that <> (different) is not the dual operation of = (equal). <> compares two values, whereas = tries to unify two terms (in the general case at least). The dual to expression A = B is not (A = B). Must Unify Operator The must unify operator is a procedure, which takes expressions as arguments. It is non-associative. MustUnifyOperator: = = A == B unifies A and B; if the unification fails an exception is raised, otherwise the predicate succeeds. Therefore A == B always succeeds. Example clauses p(L) :[H|T] = L, = ... p is a procedure. An exception will be raised if it is called with an empty list, because [H|T] and L cannot unify. Logical Operators The AndOperator(s) and OrOperator(s) are formulas, which takes formulas as arguments. They are all left associative. The " , " and " and" are synonyms and so are " ;" and " or ". AndOperator: one of , and

OrOperator: one of or And (,) The evaluation of an "and" term "A, B" proceeds as follows. First the left sub-term A is evaluated. If this evaluation fails, the whole "and" term fails. If A succeeds then the right sub-term B is evaluated. If this evaluation fails, the whole "and" term fail, otherwise the "and" term succeeds. Thus the second sub-term B is only evaluated, if the first sub-term A succeeds. Example clauses ppp() :qqq(), rrr().
Visual Prolog 7.3 Language Reference Page 99 / 147

When ppp is called it will first call qqq and if qqq succeeds, then it will call rrr. If rrr succeeds, then the "and" term and subsequently the whole clause succeeds. Or (;) The evaluation of an "or" term "A; B" proceeds as follows. First a backtrack point to the second term B is created and then the first term A is evaluated. If the evaluation of the first term succeeds, then the whole "or" term succeeds and is left with a backtrack to the second term B. If the evaluation of the first term fails, the backtrack point to the second term is activated. If the backtrack point to the second term B is activated (either because the first term fails, or because something later in the execution invokes the backtrack point), then the second term B is evaluated and the whole "or" term will succeed if B succeeds. Thus an "or" term can succeed with a backtrack point and the second sub-term B is only evaluated on backtrack. Notice currently "or" terms can only be used on the outermost level in a clause body, or a goal. Subsequent versions of Visual Prolog will change this matter. Example clauses ppp() :qqq(V), write(V), fail. qqq(X) :X = 3X = 7. When ppp is called first call qqq. qqq will first create a backtrack point to X = 7 and then evaluate X = 3. Thereby X will be bound to 3 and qqq will return. Thereby V in ppp is bound to 3, V(i.e. 3) is written and then fail is met. fail always fail so control is set to the backtrack point in qqq. Backtracking also undo all bindings made since the backtrack point was created. In this case it means that V in ppp and X in qqq are unbound. Then X = 7 is evaluated in qqq and X therefore becomes bound to 7, control is returned to ppp and X is bound to 7 and written. And then fail is met again, this time there are no more backtrack points in ppp so ppp fails. Deeply Nested "or" It is possible to nest "or" deeply in clauses. clauses p(X) = Y :(X = 1, !, Z = 3 or Z = 7), Y = 2*Z. Here we have used the keyword "or", but you can also use semi-colon ";". We recommend careful usage of "or". It is mainly intended for usage in test-conditions: clauses isOutside(X) :(X < 10 or X > 90),!.

Visual Prolog 7.3 Language Reference

Page 100 / 147

"or" is a nondeterministic construction and a cut can therefore be necessary in many cases to make the code determ. Especially a cut is needed when using "or" in "if-then-else" constructions: clauses p(X) :if (X = 1 or X > 17),! then ... end if. In future version nondeterministic conditions will be allowed and a cut will be implicitly applied to the condition. This change is backwards compatible, since existing programs will not change behavior. Not The not/1 takes a term as the argument. The evaluation of not(A) first evaluates A. If A succeeds, then not(A) fails, if A fails, then not(A) succeeds. Notice that not(A) will never bind any variables, because if not(A) succeeds then A has failed, and a failed term does not bind anything. If not(A) on the other hand fails, it cannot bind any variables either, because then the term itself failed. Also notice that not(A) can never succeed with backtrack points, because if not(A) succeeds then A have failed, and a failed term cannot contain any backtrack points. This in turn means that all possibilities of success in A have been exhausted.

fail/0 and succeed/0


fail/0 and succeed/0 are two built-in nullary predicates. fail/0 always fails and succeed/0 always succeeds, besides this the predicates have no effect.

Cut
Cut "!" removes all backtrack points created since the entrance to the current predicate, this means all backtrack points to subsequent clauses, plus backtrack points in predicate calls made in the current clause before the "!". Cut: ! Example clauses ppp(X) :X > 7, !, write("Greater than seven"). ppp(_X) :write("Not greater than seven"). When ppp is executed, there is first created a backtrack point to the second clause, and then the first clause is executed. If the test "X > 7" succeeds then the cut "!" is reached. This cut "!" will remove the backtrack point to the second clause. Example

Visual Prolog 7.3 Language Reference

Page 101 / 147

clauses ppp() :qqq(X), X > 7, !, write("Found one"). ppp() :write("Did not find one"). clauses qqq(3). qqq(12). qqq(13). When ppp is executed it first creates a backtrack point to the second ppp clause and then qqq is called. The qqq will create a backtrack point to the second qqq clause and execute the first clause, thereby returning the value 3. In ppp variable X is bound to this value and then compared to 7. This test fails and, therefore, the control backtracks to the second clause of qqq. Before executing the second clause a new backtrack point to the third clause of qqq is created and then the second clause returns 12. This time the test against 7 succeeds and, therefore, the cut is executed. This cut will remove both the backtrack point left in qqq as well as the backtrack point to the second clause of ppp. Cut Scopes A cut scope is a scope to which the effect of a cut is limited. Meaning that if a cut is met within a cut scope then only backtrack points within that scope are discarded, while backtrack points outside (i.e. prior to) the cut scope remains. The clauses of a predicate is a cut scope. Meeting a cut will (at most) discard the backtrack points that was created after entrance to the predicate. Backtrack points created before entrance to the predicate will remain. Example clauses aaa() :- p1_nd(), qqq(). qqq() :- p2_nd(), !. aaa calls p1_nd, which leaves a backtrack point, and then it calls qqq. qqq calls p2_nd, which also leaves a backtrack point. Then we meet a cut. This cut is in the cut-scope of the qqq predicate, so it is only the backtrack point in p2_nd which is discarded, the one in p1_nd remains. Several terms introduce cut scopes (see the respective terms: list comprehension, if-then-else, foreach). Here we will use if-then-else to illustrate the effect of cut scopes. Consider the schematic if-then-else term: if Cond then T1 else T2 end if The condition Cond is a cut-scope, meaning that a cut inside Cond will only have effect inside Cond. Cuts inside T1 and T2, on the other hand, have effect outside the if-then-else statement. Consider this code fragment:

Visual Prolog 7.3 Language Reference

Page 102 / 147

X = getMember_nd([3,1,2]), if X = getMember_nd([3,3]), ! then write(X) else ! end if, fail getMember_nd is a nondeterministic predicate. The evaluation of this code will go as follows. First X is bound to 3 and getMember_nd leaves a backtrack point (so that X can later become 1 and then even 2). Then we evaluate the condition in the if-then-else term. The first part of this condition succeeds as 3 is a member of [3,3]. The first part also leaves a backtrack point, so that it can be examined whether X is a member several times. Now we meet a cut. This cut is inside the condition part of an if-then-else statement, so it only has local effect, meaning that it only discards the backtrack point in the second getMember_nd, but leaves the backtrack point in the first getMember_nd predicate. The whole condition succeeds and we enter the then-part and write out "3". After the if-then-else we meet fail, which backtracks us to the first getMember_nd. getMember_nd then binds X to 1, and leaves a backtrack point (so that X can later become 2). Then we evaluate the condition in the if-then-else term. The first part of this condition fails as 1 is not a member of [3,3]. So we enter the else-part. Here we meet a cut. This cut is in the else-part of a conditional term so it has effect outside the ifthen-else term and subsequently it discards the backtrack point in the first getMember_nd. When we meet the fail after the if-then-else term there are no more backtrack points in the code and it will fail. So all in all X never becomes 2.

List Comprehension
ListComprehensionTerm : [ Term || Term ] The list comprehension term is a list expression. Consider this schematic term: [ Exp || Gen ] Gen is (typically) a nondeterm term. Exp is evaluated for each solution of Gen, and the resulting Exp's are collected in a list. The Exp corresponding to the first solution of Gen is the first element in the list, etc. This list is the result of the list comprehension term. Exp must be procedure (or erroneous). Both Exp and Gen are cut scopes. The list comprehension (normally) reads: The list of Exp's such that Gen. Example [ X || X = getMember_nd(L), X mod 2 = 0 ] This reads the list of X's such that X is in L and X is even. So this expression is the even numbers of

Visual Prolog 7.3 Language Reference

Page 103 / 147

L. Example [ X + 1 || X = getMember_nd(L), X mod 2 = 0 ] Here the collected expression is more complex. This makes say the term more awkward: "the list of (X+1)'s such that ..." This expression again finds the even elements in L, but the resulting list contains all these values incremented. This term is completely equivalent to this term: [ Y || X = getMember_nd(L), X mod 2 = 0 , Y = X+1 ] This term is easier to say: "The list of Y's such that (there exists an) X which is member of L, and which is even, and Y is X+1."

Object Member Access


Whenever we have a reference to an object, we can access the object member predicates of that object. MemberAccess: Term : Identifier (Currently, the term must be a variable or a fact variable). The identifier must have the type of the term. Inside an implementation object member predicates can be invoked without reference to an object, because "This" is subsumed, see Scoping.

Domain, Functor, and Constant Access


Domains, functors, and constants are all accessed as if they are class members. Even if they are declared in an interface. This means that when they are qualified, then they are always qualified with class/interface name and a double colon.

foreach
ForeachTerm : foreach Term do Term end foreach Consider the schematic foreach term: foreach Gen do Body end foreach Gen is (typically) a nondeterm term. Body is evaluated for each solution of Gen. If/when Gen fails
Visual Prolog 7.3 Language Reference Page 104 / 147

the foreach-term succeeds without evaluating Body. Body must be procedure (or erroneous). Gen and Body are both cut scopes. The schematic foreach term resembles a fail loop: Gen, Body, fail The main (and important) difference is that a foreach-term succeeds after the iteration, whereas a fail loop fails. As a result foreach-terms can be followed by other terms and they can be properly nested. Example foreach L = list::getMember_nd(LL) do write("<< "), foreach X = list::getMember_nd(L) do write(" ", X) end foreach, write(" >>\n") end foreach. LL is supposed to be a list of lists. The outer foreach-loop iterates L through this list, so each L is a list. The inner foreach-loop iterates X through the elements of L. There are a number of things to notice:
n n

There is no comma before the keywords "do" and "end foreach". The Body of a foreach-term is a cut scope, so a cut meet in the body will not influence the iteration. A foreach-term always succeeds (or raises an exception), and no extra variables are bound after the evaluation of a foreach-term. Therefore, a foreach-term can only be used for its side effects.

Example clauses p(L) :foreach X = list::getMember_nd(L) do stdio::write(X, "\n") end foreach, stdio::write("Finished\n"). Foreach can be used instead of traditional "fail-loops": clauses p(L) :X = list::getMember_nd(L), stdio::write(X, "\n"), fail. p(_L) :stdio::write("Finished\n"). In this context it is advantageous that Body must be a procedure, because in a "fail-loop" the body may accidentally fail before reaching the fail in the loop. Another advantage is that a foreach loop succeeds when the loop is finished, whereas a fail loop fails, so that execution can continue in the same clause. Also notice that foreach can be properly nested:

Visual Prolog 7.3 Language Reference

Page 105 / 147

clauses p(LL) :foreach L = list::getMember_nd(LL) do foreach X = list::getMember_nd(L) do stdio::write(X, "\n") end foreach, stdio::write("Finished a list\n") end foreach, stdio::write("Finished all lists\n").

if-then-else
Conditionally executes a group of statements. IfThenElseTerm: if Condition then Term Elseif-list-opt Else-opt end if Elseif: elseif Condition then Term Else: else Term The following two terms are equivalents. if Cond1 then T1 elseif Cond2 then T2 else T3 end if

if Cond1 then T1 else if Cond2 then T2 else T3 end if end if Consider the schematic if then else term: if Cond then T1 else T2 end if First Cond is evaluated, if it succeeds then T1 is evaluated otherwise T2 is evaluated. Cond is not allowed to leave backtrack points; that is, it cannot be multi or nondeterm. Cond is a cut-scope (see Cut Scopes). Example clauses w(X) :if X div 2 = 0 and X > 3 then write("X is good") else write("X is bad"), nl end if, nl. There are several things to notice about this example:
n n

You can use "and" and "or" logical operators and other "complex" terms in all three sub-terms. There is no comma before the keywords "then", "elseif", "else", and "end if".

Visual Prolog 7.3 Language Reference

Page 106 / 147

For readability sake, we always recommend using "or" instead of ";". Likewise we also recommend using "and" (instead of ",") when it (as in the condition above) represents a logical "condition" rather than a "sequentation". Leaving out the else-part is just shorthand for writing that else succeed, i.e. if Cond then Term end if is short-hand for if Cond then Term else succeed end if

try-catch-finally
The try-catch-finally statement provides means for dealing with exceptions that may occur in a given block of code. TryCatchTerm: try Term CatchFinally-list end try CatchFinally: one of catch Variable do Trap-Handler finally Finally-Handler Handler: Term A try-construction thus have a Term and a list of catch and finally handlers. The Term and the handlers are not allowed to leave backtrack points (i.e. they cannot have mode multi or nondeterm). A try-construction with more than one handler is equivalent to nesting several try-constructions with one handler each. I.e. the following term: try Body catch Var1 do Handler1 finally Handler2 catch Var2 do Handler3 end try Is equivalent to these nested terms: try try try Body catch Var1 do Handler1 end try finally Handler2 end try catch Var2 do
Visual Prolog 7.3 Language Reference Page 107 / 147

catch Var2 do Handler3 end try try-catch Consider the try-catch construction try Body catch Var do Handler end try First Body is evaluated. If Body fails or succeeds the whole try construction fails or succeeds, respectively. I.e. if Body does not terminate with an exception the try construction corresponds to evaluating Body. If Body terminates with an exception, then the exception is caught by the catch handler. Meaning that first Var is bound to the exception (in PFC context the exception will be a traceId) and then Handler is evaluated. In this case the construction behaves as if Handler is evaluated with Var bound to the caught exception. Notice, that no bindings are made by Body if it terminates with an exception. Example Handle the situation where a file cannot be read: clauses read(Filename) = Contents :try Contents = file::readFile(Filename) catch TraceId do stdio::writef("Couldnotreadthefile:%\n", Filename), exceptionDump::dumpToStdio(TraceId), Contents = "" end try. First Contents = file::readFile(Filename) is evaluated, if that does not terminate with an exception read returns the contents of the file. If it raises an exception the handler is evaluated with TraceId bound to the exception. So in this case a message is written to stdio and then the exception is dumped to stdio, and finally Contents is set to the empty string which is returned as result. try-finally Consider the try-finally construction: try Body finally Handler end try The purpose of the construction is to evaluate the Handler after the Body no matter how the Body terminates, i.e. whether it succeeds, fails or terminates with an exception (it cannot leave backtrack points).

Visual Prolog 7.3 Language Reference

Page 108 / 147

The evaluation is like this First Body is evaluated.


n n n

If Body succeeds: Handler is executed and the try-finally construction succeeds. If Body fails: Handler is executed and the try-finally construction fails. If Body terminates with an exception Exn: Handler is executed and the try-finally construction terminates with the exception Exn.

Example Ensure that an odbcStatement is free'd after use: clauses tryGetName(Connection, PersonId) = Name :Stmt = odbcStatement::new(Connection), try Stmt:setParameterValue(1, core::integer(PersonId)), Stmt:execDirect("select name from person where id=?"), Stmt:fetch(), Name = Stmt:getParameterValue_string(1) finally Stmt:free() end try. The Stmt is free'd also if fetch fails, or if something terminates with an exception.

Visual Prolog 7.3 Language Reference

Page 109 / 147

Conversion
View and Construction Types
An interface defines a type of objects, all objects that supports the interface have that type. In the sequel we shall use the term the object type as synonym for the term the type defined by the interface. Since interfaces define types, these types can be used as formal type specifiers in predicate and fact declarations and in domain definitions. Since an object have the object type of any interface it supports, it can be used as an object of any of these types. I.e. the type of objects is converted to any supported object type. As described below the conversion is in many cases performed automatically. So the same object can be viewed as having different types in different contexts. The type with which an object is viewed is called its view type, whereas the type of the class that constructed the object is called the construction type or definition type. The construction type is also a view type. Type Conversion As mentioned above objects can be used as having the type of any supported interface. This section describes how conversions between various supported types is handled. Conversion Upwards If some term is statically typed to some type T1 and T1 is declared to support T2 then it is obvious that any object referenced by the variable will indeed support T2. So upward support information is statically known. Subsequently all conversions upwards in the support hierarchy is performed automatically. Example Assume the existence of the interface bb which supports an interface aa and the class bb_class with construction type bb. Consider the following code: implement ... predicates ppp : (aa AA). clauses ... :BB = bb_class::new(), % (1) ppp(B). % (2) clauses ppp(AA) :- % (3) ... BB = convert(bb,AA), % Conversion possible since definition type of AA is bb ... In the line marked (1) we create a bb_class object: the object has construction type bb. The variable BB is a reference to this new object. BB provides the view type bb on the object. In the line marked (2) the object is passed to ppp as an aa object. The conversion from view type bb to view type aa is performed implicitly. When the object reaches the line marked (3) it has view-type aa, though the construction type is still bb.

Explicit Conversion
Explicit conversion is performed by calling a conversion predicate. Several conversion predicates are available.

Visual Prolog 7.3 Language Reference

Page 110 / 147

Checked Conversion The predicates convert/2-> and tryConvert/2-> are used to perform safe conversion from one type to another type. Neither predicate can be given a real declaration, but here are pseudo declarations for them predicates convert : ("type" Type, _ Value) -> Type ConvertedValue. tryConvert : ("type" Type, _ Value) -> Type ConvertedValue determ. Both convert/2-> and tryConvert/2-> take a "type" as the first argument and a value of any type as the second argument and will then return the converted value as the result. convert/2-> will raise an exception if the conversion is impossible, while tryConvert/2-> simply fails in that case. Notice that the use of convert/2-> and tryConvert/2-> is always superfluous, if the source type is a subtype of the target type, because then the conversion will be performed implicitly. convert/2-> and tryConvert/2-> can be used in the following situations:
n n

converting from one number domain to another number domain converting an object to another type

The compiler may complain (but does not have to) if it can determine that a conversion can never succeed, for example if attempting to convert between number domains that does not have overlapping ranges. Conversion Downwards When an object is converted to a super type (i.e. to a supported interface), then information about the object is "forgotten". Notice that the capabilities are not really lost they are just not visible in the context where the object is seen with a less capable interface. In many situations it is necessary to restore the actual capabilities of the objects. Therefore, we need to be able to convert them downward as well as upwards. Downward conversion cannot (in general) be validated statically. Therefore, it is necessary to use explicit conversion when restoring "lost" interfaces. Example While it is extremely simple to make sensible illustration of type conversions up in the supportshierarchy, it requires a "real" example to illustrate sensible use of downward conversion. Therefore we shall present a more "real" example here. Assume that we want to implement "sets of homogeneously typed objects". I.e. sets of objects which all supports a certain view type. We know that we will need such sets for several types of objects. Therefore we want to make our implementation in a way, which can easily be adopted to many different types of objects, but yet preserve the homogeneity of the contained objects. Our approach is fairly standard: we make the actual implementation of the "set" based on the object type, which any object supports. And then construct the more specific versions of "sets" by means of a thin layer, which will convert between the actual type and object. We shall not show the actual implementation of object sets, we shall merely assume that it exists in the shape of the following class and interface:

Visual Prolog 7.3 Language Reference

Page 111 / 147

interface objectSet predicates insert : (object Elem). getSomeElem : () -> object determ. ... end interface class objectSet_class : objectSet end class Now assume that we have some object type myObject and that we want to create the corresponding "set" class myObjectSet_class. We declare myObjectSet_class as following: interface myObjectSet predicates insert : (myObject Elem). getSomeElem : () -> myObject determ. ... end interface class myObjectSet_class : myObjectSet end class I.e. myObjectSet has all the predicates of objectSet but every occurrence of object is replaced with myObject. The implementation of myObjectSet_class inherits from objectSet_class, this embedded/inherited objectSet will carry the members of the set. The implementation will fulfill the following invariant: The embedded objectSet will only contain objects of type myObject (even though they "technically" have type object). The implementation looks as follows: implement myObjectSet_class inherit objectSet_class clauses insert(Elem) :objectSet_class::insert(Elem). % (1) getSomeElem() = Some :SomeObject = objectSet_class::getSomeElem(), % (2) Some = convert(myObject, SomeObject). % (3) ... end implement In the line marked (1) Elem is automatically converted from type myObject to object. In the line marked (2) we retrieve an object from the embedded object set. Technically this object has type object. But from our invariant we know that the object also supports myObject. Subsequently, we know that we can safely restore the myObject interface. This is explicitly done in the line marked (3). Private and Public Types When an object is created with a constructor it is returned with the construction type. Such an object can automatically be converted to any supported interface and explicitly back again. Even if the class that implements the object have stated further supported interfaces privately it is impossible to convert the "public" object to any of these private types. In the implementation however the object can be accessed with any privately supported type. Furthermore "This" can be handed outside the implementation with any of these privately supported types. Such a "private" version of an object can also be converted implicitly upwards in its hierarchy and explicitly downwards again. In fact such a "private" object can be converted explicitly to any publicly or privately supported interface.
Visual Prolog 7.3 Language Reference Page 112 / 147

So an object have two views the public view and the private view. The private view includes the public type. The object cannot be converted from one view to another, but since the private view includes the public type, the private view can be converted to any supported type whatsoever. Unchecked Conversion The predicate uncheckedConvert/2 is used to perform unsafe conversions based on memory representation. The predicate does not modify memory in any way, it simply forces the compiler to interpret that piece of storage with another type. Notice this predicate is highly unsafe and should be used with maximum precautions. The predicate is intended to be used when interfacing to foreign languages, in order to interpret the memory images these foreign languages uses. uncheckedConvert/2 can only be used on pieces of memory that have exactly the same bit-size. However many kinds of data are represented by a pointer and such data have the same bit-size. predicates uncheckedConvert : ("type" Type, _ Value) -> Type ConvertedValue. Example

Visual Prolog 7.3 Language Reference

Page 113 / 147

Exception Handling
This section describes the low level constructions for dealing with exceptions in Visual Prolog. PFC does however put a higher level layer on top of this low level mechanisms (see the tutorial Exception Handling). The basic part of the exception handling system is based on the built-in predicate errorExit/1 and the try-catch language construction.
n n

errorExit/1 raises an exception try-catch sets an exception handler for a certain computation.

When errorExit/1 is called the currently active exception handler is invoked. This exception handler is executed in its original context, i.e. in the context where it was set rather than in the context where the exception is raised. The argument that errorExit/1 is invoked on is transferred to the exception handler. This argument must somehow provide the needed description of the exception. Together with additional runtime routines, it is possible to build high-level exception mechanisms on top of this system. It is however out of the scope of this document to describe runtime system access routines. It is likewise out of the scope of this document to describe how the runtime system deals with exceptions occurring inside the runtime system. The first argument of try-catch is the term to execute with new exception handler. The second argument must be a variable. This variable will be bound to the value errorExit/1 is invoked on, if it is invoked while this exception handler is active. The third argument is the exception handler, which will be invoked if errorExit/1 is called while this exception handler is active. The exception handler can access the variable stated in the second argument thereby examining the exception that was raised. Example clauses p(X) :try dangerous(X) catch Exception do handleDangerous(Exception) end try. If an exception is raised while executing dangerous, then Exception will be bound to the exception value, and control will be transferred to the third argument of try-catch. In this case Exception is passed to handleDangerous.

Visual Prolog 7.3 Language Reference

Page 114 / 147

Built-in entities
Visual Prolog contains an embedded hidden class, which provides declarations and implementations to all built-in constants, domains, and predicates. These built-in constants, domains, and predicates can be used both during compilation (for example, in #if ... constructions) and in implementations (which are supported for runtime). Each compilation unit implicitly contains the declaration of this embedded hidden class. To disambiguate from other entities with the same name you can use "::" before names of built-in items. Notice that the clause variable This is automatically defined in the clauses for object predicates.

Operators
See also Operators. Operator ^ - (unary) *, / div, mod quot, rem +, n n n n

Description Power operation Unary minus Multiplication and division The quotient and remainder of an integral division rounded towards minus infinity The quotient and remainder of an integral division rounded towards zero Addition and subtraction

Remark Not defined for 64 bit integral numbers

Not defined for real's Not defined for real's

The operators are listed from highest to lowest precedence All division and multiplication operators have same precedence. The the power operator is right associative All other operators are left associative.

All binary operators takes two arguments of same base type and returns a value of that base type. Operands and result may be converted using ordinary subtype rules. Integral division div and quot are different integral division operators.
n n

div rounds towards minus infinite. mod is the remainder corresponding to div. quot rounds towards zero. rem is the remainder corresponding to quot.

For positive results div and quot have same functionality. The difference can be seen in this table: A 15 B A div B A mod B A quot B A rem B 7 2 -3 -3 2 1 6 -6 -1 2 -2 -2 2 1 -1 1 -1

-15 7 15 -7 -15 -7

Constants
Visual Prolog 7.3 Language Reference Page 115 / 147

compilation_date compilation_time

Compilation date. Compilation time.

compiler_buildDate Build date of a compiler. compiler_version maxFloatDigits null nullHandle invalidHandle platform_bits platform_name compilation_date Compilation date. Here Y Y Y Y means the number of a year, MM means a month number, and DD means a day number. compilation_date : string = "YYYY-MM-DD". compilation_time Compilation time. Here HH means hours, MM means minutes, and SS means seconds. compilation_time : string = "HH-MM-SS". compiler_buildDate Build date of the compiler. compiler_buildDate : string = "YYYY-MM-DD HH-MM-SS". compiler_version A compiler version. This value depends upon the compiler version. compiler_version = 6003. maxFloatDigits Defines the maximal value of "digits", which is supported by the compiler. maxFloatDigits = 19. null A special constant of a pointer type with the zero value. null : pointer = uncheckedConvert(pointer, 0). A compiler version. Defines the maximal value of "digits", which is supported by the compiler. The default NULL pointer. A special constant of a handle type with the zero value. A special constant of a handle type with the invalid (-1) value. Defines the digital capacity of compilation platform. Defines the target platform name.

Visual Prolog 7.3 Language Reference

Page 116 / 147

nullHandle A special constant of a handle type with the zero value. nullHandle : handle = uncheckedConvert(handle, 0). invalidHandle A special constant of a handle type with the invalid (-1) value. invalidHandle : handle = uncheckedConvert(handle, 0xFFFFFFFF). platform_bits Defines the digital capacity of compilation platform. platform_bits = 32. platform_name Defines the target platform name. platform_name : string = "Windows 32bits".

Domains
char string string8 symbol binary Wide (two-bytes) character. Wide zero-terminated sequence of wide characters. Zero-terminated sequence of ASCII (one-byte) characters. Wide zero-terminated sequence of wide characters. Sequence of bytes.

binaryNonAtomic Sequence of bytes. integer integer64 unsigned unsigned64 real real32 pointer handle boolean factDB compareResult char Integral signed integer number. Integral signed integer number. Integral unsigned integer number. Integral unsigned integer number. Float-pointing number. Float-pointing number. 4-bytes pointer to a memory address. 4-bytes pointer to a memory address. Boolean values. Descriptors of named internal databases. Values of comparison result.

Visual Prolog 7.3 Language Reference

Page 117 / 147

Wide character. char The values of this domain are UNICODE characters. Implemented as 2 unsigned bytes. Only assignment and comparison (in the lexicographical sense) operations are applied to the values of this domain. The image of a character has the following syntax: Char_image : ' Char_value ' Char_value : Letter Digit Graphical_symbol \ Escape_seq Escape_seq: t n r \ ' " u HHHH In the syntax above HHHH correspond to 4 hexadecimal digits. Also, the backslash symbol and the single quote can be represented by an escape-sequence only. compareResult The compareResult is a built-in domain. It is used to define a comparison result. The built-in compare predicate's result is compareResult domain. domains compareResult = less; equal; greater. string Wide zero terminated sequence of wide characters. string A string is a sequence of UNICODE characters. It's implemented as a pointer to the wide zeroterminated array of wide characters. Only assignment and comparison (in the lexicographical sense) operations are applied to values of this domain. In source code a string literal can be specified as a set of sequences of characters surrounded by the double quotes. StringLiteral: StringLiteralPart-list

StringLiteralPart : @" AnyCharacter-list-opt " " CharacterValue-list-opt "

Visual Prolog 7.3 Language Reference

Page 118 / 147

A string literal consists of one or more StringLiteralPart's, which are concatenated. StringLiteralPart's starting with @ does not use escape sequences, whereas StringLiteralPart's without @ uses the following escape sequences:
n n n n n n n

\\ representing \ \t representing Tab-character \n representing newline-character \r representing carriage return \' representing single quote \" representing double quote \u followed by exactly four HexadecimalDigit's representing the Unicode character corresponding to the digits.

The double quotes in the string can be represented by the escape-sequence only (the single quote can be represented both with an escape-sequence and a graphical symbol). string8 A term of the built-in string8 domain is a sequence of ASCII (one-byte) characters. It is implemented as a pointer to the zero terminated array of ASCII characters. Only assignment and comparison for equality (in the lexicographical sense) operations are applied to the values of this domain. Currently no literals are allowed for this domain. symbol Wide zero terminated sequence of wide characters. symbol Similar to a string, a symbol is also a sequence of the UNICODE characters. It's implemented as a pointer to an entry in a symbol table that contains strings. The operations that can be applied to symbols are the same as for strings. The image of a symbol is represented with a <string_literal> (any string surrounded by the double quotes). Symbols and strings are largely interchangeable but they are stored differently. Symbols are kept in a look-up table and their addresses, rather than the symbols themselves, are stored to represent objects. This means that symbols can be matched very quickly and, if a symbol occurs repeatedly in a program, it can be stored very compactly. Strings are not kept in a look-up table. Visual Prolog examines strings character-by-character whenever they are to be matched. binary Sequence of N bytes. binary Values of this domain are used for holding binary data. A binary value is implemented as a pointer to the sequence of bytes that represents the contents of a binary term. The length of a binary term is situated in the 4 bytes immediately preceding this sequence of bytes. The 4 bytes contains: TotalNumberOfBytesOccupiedByBinary = ByteLen + 4

Visual Prolog 7.3 Language Reference

Page 119 / 147

where ByteLen - is the length of the binary term and 4 is number of bytes occupied by size field. Only assignment and comparison operations are applied to values of binary domain. Two binary terms are compared in the following way:
n n

If they are of different sizes, the bigger is considered larger. Otherwise, they are compared byte by byte, as unsigned values. Comparison stops when two differing bytes are found and the result of their comparison is the result of the comparison of the binary terms. Two binary terms are equal if they have the same sizes and all bytes are equal.

The text syntax for binary images is determined by the Binary rules: Binary : $ [ Byte_value-comma-sep-list-opt ] Byte_value : Expression Each expression should be calculate on compiling time and its value should be in the range from to 255. binaryNonAtomic Sequence of N bytes. binaryNonAtomic Same as binary, but can contain pointer. integer Integral signed number. integer Values of this domain occupy 4 bytes. Arithmetic operations (+, -, /, *, ^), comparison, assignment, div, mod, quot, and rem operations are applied to values of this domain. The permitted number range is from -2147483648 to 2147483647. The syntax for the integer literal is determined by the Integer rule:

Visual Prolog 7.3 Language Reference

Page 120 / 147

Integer : Add_operation-opt 0o Oct_number Add_operation-opt Dec_number Add_operation-opt 0x Hex_number Add_operation : + Oct_number : Oct_digit-list Oct_digit : one of 01234567 Dec_number : Dec_digit-list Dec_digit : one of Oct_digit 8 9 Hex_number : Hex_digit-list Hex_digit : one of Dec_digit a b c d e f A B C D E F integer64 Integral signed number. integer64 Values of this domain occupy 8 bytes. The permitted number range is from -2^63 = -9,223,372,036,854,775,808 to 2^63-1 = 9,223,372,036,854,775,807. The syntax for integer64 literal is the same as Integer rule. The set of operations for integer64 is similar to the one for Integer. unsigned Integral unsigned number. unsigned Values of this domain occupy 4 bytes. Arithmetic operations (+, -, /, *, ^), comparison, assignment, div/2->, mod/2->, rem/2->, and quot/2-> operations are applied to values of this domain. The permitted number range is from to 4294967295. The syntax for unsigned number images is the same as for integer numbers. The usage of minus sign (UnaryMinus) is not allowed for an image of an unsigned number. unsigned64 Integral unsigned number. unsigned64 Values of this domain occupy 8 bytes. The permitted number range is from to 2^64-1 = 18,446,744,073,709,551,615.
Visual Prolog 7.3 Language Reference Page 121 / 147

The syntax for unsigned64 number images is the same as for integer64 numbers. The usage of minus sign (UnaryMinus) is not allowed for an image of an unsigned64 number. The set of operations for unsigned64 is similar to the one for Unsigned. real Float-pointing number. real Values of this domain occupy 8 bytes. This numerical real domain is introduced for the user's convenience only. All arithmetic, comparison, and assignment operations are applied to values of real domain. The permitted number range is -1.7e+308 to 1.7e+308. Values from integral domains are automatically converted to real numbers when necessary. The syntax for the floating-point number literal is determined by the Real rule: Real : Add_operation-opt Fraction Exponent-opt Fraction : Dec_number Fractional_part-opt Fractional_part : . Dec_number Exponent : Exp Add_operation-opt Dec_number Exp : e E Add_operation : + Dec_number : Dec_digit-list Dec_digit : one of 0123456789 real32 Float-pointing number. real32 Values of this domain occupy 4 bytes. This numerical real32 domain is introduced for the user's convenience only. All arithmetic, comparison, and assignment operations can be applied to values of real32 domain. The permitted number range is -3.4e+38 to 3.4e+38. The syntax of real32 literals is the same as real lietrals. pointer A pointer to a memory address. pointer
Visual Prolog 7.3 Language Reference Page 122 / 147

pointer A pointer directly corresponds to memory addresses. Only the equality operation can be applied to the values of this domain. There is a built-in null constant for this type handle A handle is used for Windows API function call. Values of this domain occupy 4 bytes. There are no operations for this domain and cannot be converted (except uncheckedConvert) to/from other domains. There is a built-in nullHandle and invalidHandle constant for this type boolean Boolean values. boolean This domain is introduced for the user convenience only. It is treated as usual compound domain with the following definition: domains boolean = false(); true(). factDB Descriptors of named internal databases. factDB This domain has the following hidden meta-declaration: domains factDB = struct @factdb( named_internal_database_domain, object ). All user-defined names of facts sections are the constants of this domain. The compiler automatically builds the corresponding compound terms from such constants whenever it's in need. At the runtime the 1st field of this structure contains the address of the corresponding domain descriptor and the 2nd field contains either zero (for class facts sections) or pointer to an object (i.e. This, for object facts sections).

Predicates
assert/1 asserta/1 assertz/1 bound/1 determ Insert the specified fact at the end of the matched internal facts database. Insert a fact at the beginning of the matched internal facts database. Insert a fact at the end of the matched internal facts database. Test whether the specified variable is bound to a value. This compile time predicate returns the string ClassName that represents

Visual Prolog 7.3 Language Reference

Page 123 / 147

class_Name/0-> compare/2-> convert/2-> digitsOf/1-> errorExit/1 erroneous fail/0 failure free/1 determ hasDomain/2 isErroneous/1 determ lowerBound/1-> maxDigits/1-> not/1 determ

This compile time predicate returns the string ClassName that represents the name of the current interface or class. Returns the result of the variables' comparison. Checked term conversion. Returns precision of the specified floating-point domain. Performs a run-time error with the specified return code ErrorNumber and sets the internal error information. Invoke backtracking. Check whether a variable is free. Checks whether the variable VariableName has the domain domainName. Returns the lower bound value of the specified numeric domain. Returns the lower bound value of the specified numeric domain. Retrieves the value of digits (precision) of the basic domain corresponding to the specified floating-point domain domainName. Negate the result (success/fail) of subgoal. This compile time predicate returns the string PredicateFullName that represent the name of the predicate in which clause body predicate_name is called. The returned predicate name is qualified with a scope's name. This compile time predicate returns the string PredicateName that represents the name of the predicate in which clause body predicate_name is called. Remove a matched fact from the matched internal facts database. Remove all matching facts from the matched internal facts database. Remove all facts from the specified named internal facts database. Retrieves the number of bits occupied in memory by an entity of the specified domain DomainName. Retrieves the number of bytes occupied in memory by the specified term. Retrieves the number of bytes occupied in memory by the entity of the specified domain DomainName. Returns the current line number in the source file processed by the compiler . Returns the name of the source file processed by the compiler.

predicate_fullname/1->

predicate_name/0-> retract/1 nondeterm retractall/1 retractFactDb/1 sizeBitsOf/1-> sizeOf/1-> sizeOfDomain/1-> sourcefile_lineno/0-> sourcefile_name/0->

sourcefile_timestamp/0- Returns the string representing the date and time of the source file > processed by the compiler. succeed/0 toBinary/1-> toBoolean/1-> toString/1-> toTerm/1-> toTerm/2-> The predicate succeed/0 will always succeed. Converts the specified Term to the binary representation. The purpose of this meta-predicate is to convert the deterministic call (to a predicate or fact) to the procedure that returns the value of boolean domain. Converts the specified Term to the string representation. Converts the string/binary representation of the specified term SrcTerm into representation corresponding to the domain of PrologTerm variable of the return value.

Converts the string/binary representation of the specified term SrcTerm tryToTerm/1-> determ into representation corresponding to the domain of PrologTerm variable tryToTerm/2-> determ of the return value. Checks whether the input term InputTerm can be strictly converted into tryConvert/2-> determ the specified domain returnDomain and returns the converted term ReturnTerm. uncheckedConvert/2-> Unchecked conversion of domains.
Page 124 / 147

Visual Prolog 7.3 Language Reference

uncheckedConvert/2-> upperBound/1->

Unchecked conversion of domains. Returns the upper bound value of the specified numeric domain.

The following predicates are deprecated: finally/2 findall/3 Use try ... finally ... end try instead. Use list comprehension [...||...] instead

trap/3 determ Use try ... catch V do ... end try instead assert assert : (<fact-term> FactTerm). Insert the specified fact at the end of the matched internal facts database assert(Fact) inserts Fact in the matched internal facts database after any other stored facts for the corresponding database predicate. Fact must be a term belonging to the domain of an internal facts database. assert/1 applied to a single fact changes the existing instance of a fact to the specified one. assert/1 has the same effect as assertz/1. See also asserta/1 Notice that the combination of retract/1 and assert/1 like the following can lead to endless loop: loop() :retract(fct(X)), ... % creating Y from X assert(fct(Y)), fail. The problem is that the retract in first line will eventually retract the fact asserted in the last line, because that fact is inserted last in the fact chain. Exceptions:
n

Attempt to a fact declared as determ, but the fact instance already exists.

asserta asserta : (<fact-term> FactTerm). Insert a fact at the beginning of the matched internal facts database. The asserta(Fact) predicate inserts a Fact in the matched internal facts database before any other stored facts for the corresponding predicate. The Fact must be a term belonging to the domain of an internal facts database. The asserta/1 applied to a single fact changes the existing instance of a fact to the specified one. See also assert/1 and assertz/1. Exceptions:
n

Attempt to a fact declared as determ, but the fact instance already exists.

assertz assertz : (<fact-term> FactTerm).

Visual Prolog 7.3 Language Reference

Page 125 / 147

assertz does exactly the same as the assert/1 predicate. bound bound : (<variable> Variable) determ. Test whether the specified variable is bound to a value. The bound(Variable) succeeds if Variable is bound and fails if it is free. The bound predicate is used to control flow patterns and to check the binding of reference variables. The bound predicate treats the specified Variable as bound if any of it's part is instantiated. See also free/1. class_Name class_Name : () -> string ClassName. This compile time predicate returns the string ClassName that represents the name of the current interface or class. compare compare : (A Left, A Right) -> compareResult CompareResult. Comparison of two terms of the same domain, resturns the value of compareResult domain. CompareResult = compare("bar", "foo") convert convert : (<type> Type, Term) -> <type> Converted. Checked term conversion. Call-template for this function is: ReturnTerm = convert(returnDomain, InputTerm)
n

returnDomain: Specifies a domain to which function convert/2-> converts InputTerm. Here returnDomain must be a name of built-in Visual Prolog domain, an interface domain, a name of such user defined domain that is synonym to one of built-in Visual Prolog domains, a numeric domain, binary and pointer domains. The domain name returnDomain must be specified at compiletime, i.e. it cannot come from a variable. InputTerm: Specifies the value that must be converted. InputTerm may be any Prolog term or an expression. If InputTerm is an expression, then it will be evaluated before the conversion. ReturnTerm: Returned parameter ReturnTerm will be of returnDomain type.

The convert predicate performs a clean and genuine conversion of the given InputTerm, returning a new term ReturnTerm of the specified new domain returnDomain. If convert cannot perform the required conversion, it rises errors. The similar functionality is provided by the tryConvert/2-> predicate, but tryConvert-> fails and does not produce any runtime errors if it cannot perform the conversion.

Visual Prolog 7.3 Language Reference

Page 126 / 147

Allowed conversions
n n n n n n

Between numerical domains. Between interface types. Between string and symbol domains. From binary to pointer. For synonyms of mentioned domains. Between reference domains and corresponding non-reference domains.

The contrast to these is uncheckedConvert/2-> predicate, which performs an unchecked conversion between terms from any domains, which have the same bit-size. The convert/2-> (or tryConvert/2->) predicate accomplishes a checked explicit conversion, when the source and target domains are statically known during the compilation. The result of an explicit conversion can be one of the following:
n n

ok the successful conversion to the target domain; run-time-check the conversion to the target domain with generation of run-time checking for compatibility; error the conversion is impossible, error output.

Rules of Checked Explicit Conversions


n

n n n

n n n

Synonyms of domains are converted using the same rules that are applied to the domains themselves. Numerical domains can be converted to the numerical domains only. Integral constants are the representatives of the anonymous integral domain: [const .. const]. Real constants are the representatives of the anonymous real domain: digits dig [const .. const], where dig is the number of the digits in mantissa without insignificant zeroes. A value of the symbol domain can be converted to the string domain and vice versa. A value of binary domain can be converted to the pointer domain. The domains that are implicitly introduced for interfaces can be converted only to the interface domains according to the rules specified below. All other domains cannot be converted.

Conversions of Numerical Domains


n

The range is considered first during such conversion. If the ranges of source and target do not intersect, then an error is produced. If the ranges of source and target only partially intersect, then run-time checking is generated. Also, if one of domains is real and another is an integral one, then the integer range is converted to the real range before the comparison. When input term in real and output is integer, then convert/2-> and tryConvert/2-> predicates truncate the input value to the nearest integer value, which is nearer to zero.

Conversions of Interface Types Predicate convert/2-> allow to convert any object to any interface type. The actual correctness of such conversion is checked at runtime. When object is created, its type is internally stored, therefore when the object is passed as argument it still remember about its original type. This original type is used for checking allowed conversions. The example: interface x supports a, b end interface x If object is created by class, which implements x interface, and then object is passed as parameter of type a to some predicate, then it is allowed to convert the object to b type. Exceptions:

Visual Prolog 7.3 Language Reference

Page 127 / 147

n n

Check range error. Unsupported interface type.

digitsOf digitsOf : (<real-domain> Domain) -> unsigned. Returns precision of the specified floating-point domain. Call-template for this function is: Precision = digitsof(domainName) The input parameter domainName of this compiling-time predicate is a floating-point domain, it should be explicitly specified at compile-time (that is, domainName cannot come from a variable). The predicate returns the number Precision that was determined by the digits attribute in the domain declaration. The compiler guarantees that values of the domain domainName will have at least Precision number of significant decimal digits. errorExit errorExit : (unsigned ErrorNumber) erroneous. Performs a run-time error with the specified return code ErrorNumber, which can be used in the trycatch-finally. fail fail : () failure. The fail predicate forces failure and, hence, always causes backtracking. A clause that fails (with fail or for some other reason) cannot bind output arguments. free free : (<variableName> Variable) determ. Check whether a variable is free. Call-template for this predicate is: free(Variable) The free predicate succeeds if the specified Variable is free and fails if Variable is bound. The free predicate treats the specified Variable as bound if any of it's part are instantiated. See also bound/1. hasDomain

Visual Prolog 7.3 Language Reference

Page 128 / 147

hasDomain : (<type> Type, <variable> Variable) procedure. hasDomain is not really a predicate, but more a declaration: It states that the variable Variable must have the type Type. The variable can be free, bound or of some mixed flow. The binding of the variable is not changes in any way. lowerBound lowerBound : (<numeric-domain> NumericDomain) -> <numeric-domain> LowerBound. Returns the lower bound of the specified NumericDomain. Call-template for this function is: LowerBoundValue = lowerBound(domainName) The lowerBound is a compiling-time predicate. The lowerBound returns the lower bound value LowerBoundValue of the specified numeric domain domainName. The return value LowerBoundValue belongs to the same domain domainName. The domainName parameter should be the name of any numerical domain; this domain name should be explicitly specified at compile-time (that is, domainName cannot come from a variable). See also upperBound/1->. It will give a compile time error if the specified domain domainName is not numeric domain. isErroneous isErroneous : (<fact-variable> FactVariable) determ. The predicate succeeds if the specified fact variable is erroneous. Call-template for this predicate is: isErroneous(factVariableName) The predicate succeeds if the specified fact variable factVariableName has the erroneous value, otherwise it fails. maxDigits maxDigits : (<real-domain> RealDomain) -> unsigned MaxDigits Retrieves the value of digits (precision) of the basic domain corresponding to the specified floatingpoint domain domainName. Call-template for this function is: MaxDigitsNumber = maxdigits(domainName)

Visual Prolog 7.3 Language Reference

Page 129 / 147

The return maximal number of digits MaxDigitsNumber for the domainName parameter, which should be the name of a real domain. not not : (<term> SubGoal) determ. Succeds if the SubGoal fails, and vice versa. Call-template for this predicate is: not(SubGoal) The not succeeds if SubGoal fails when evaluated. Notice that SubGoal cannot bind any variables, because not(SubGoal) only succeeds if SubGoal fails (and a failing goal does not bind anything). predicate_fullname predicate_fullname : () -> string PredicateFullName. This predicate returns the name PredicateFullName of the predicate in which it is invoked. The returned predicate name is qualified with a scope name. predicate_fullname can only be used inside a clause. Use of predicate_fullname in other places causes a compile time error. See also predicate_name. predicate_name predicate_name : () -> string PredicateName. This predicate returns the name PredicateName of the predicate in which it is invoked. predicate_name can only be used inside a clause. Use of predicate_name in other places causes a compile time error. See also predicate_fullname retract retract : (<fact-term> FactTerm) nondeterm anyflow. Successively removes the first matching fact from the facts database. Fails when no more facts match. Call-template for this predicate is: retract(FactTemplate) Here FactTemplate should be a fact term. The retract/1 predicate deletes the first fact that matches the FactTemplate in the appropriated facts database. During backtracking, the rest of the matching facts will be deleted. Notice that FactTemplate can have any level of instantiation. The FactTemplate is matched with the facts in the facts database, which means that any free variables will be bound in the call to
Visual Prolog 7.3 Language Reference Page 130 / 147

retract/1. The FactTemplate can contain any anonymous variables. That is, variables with names consisting from the single underscore _ or a variable with a name starting with an underscore _AnyValue if the variable occurs only once in the clause. For example. retract(person("Hans", _Age)), will retract the first matched person fact that has "Hans" as the first argument and anything as the second argument. When retracting a fact, which is declared to be determ, the call to retract/1 will be deterministic. See also retractall/1 and retractFactDb. The retract/1 predicate cannot be applied to single facts or fact variables. Be careful calling retract/1 with free FactTemplate variable if any single fact is declared in the project current scope. If you retract a single fact, then the run-time error is generated. The retract/1 predicate fails when there are no more matches. retractall retractall : (<fact-term> FactTerm) . Remove all matching facts from the facts database. Call-template for this predicate is: retractall(FactTemplate) Here FactTemplate should be a fact term. The retractall/1 retracts all facts which match the given FactTemplate. It always succeeds, even if no facts were retracted. Attempting to retract a single fact will cause a compile time error. It is not possible to obtain any output values from retractall/1. For this reason, the variables in the call must be bound or be a single underscores (anonymous). Notice that FactTemplate can have any level of instantiation, but free variables must be single underscores ("unconditionally anonymous"). In difference to retract/1 "conditionally" anonymous variables with names starting from the underscore (like _AnyValue) cannot be used in retractall/1. See also retract/1 and retractFactDb/1. retractFactDb retractFactDb : (factDB FactDB). Remove all facts from the named internal facts database FactDB. Call-template for this predicate is:

Visual Prolog 7.3 Language Reference

Page 131 / 147

retractFactDb(FactDB) The retractFactDb/1 removes all facts from the named facts database FactDB. Notice, it is impossible to retract single facts and fact variables, so the predicate leaves such ones as they are. See also retractall/1 and retract/1. retractAll/2 Obsolete predicate! Use retractFactDb/1 instead. sizeBitsOf sizeBitsOf : (<domain> DomainName) -> unsigned BitSize. Retrieves the number of bits occupied in memory by an entity of the specified domain DomainName. Call-template for this function is: BitSize = sizeBitsOf(DomainName) This compiling-time predicate receives the domain DomainName as input parameter and return the size of memory that is occupied by the entity of the given domain. The result is measured in bits. For the integer domains sizeBitsOf/1-> predicate returns the value that was defined for the size-field in a domain's declaration. The following is always true for the integral domains: sizeOfDomain(domain)*8 - 7 < sizeBitsOf(domain) < sizeOfDomain(domain)*8 = = See also sizeOfDomain/1->. sizeOf sizeOf : (<term> Term) -> integer ByteSize. Retrieves the number of bytes occupied in memory by the specified term Term. Call-template for this function is: ByteSize = sizeOf(Term) The sizeOf/1-> function receives a term as input parameter and returns value ByteSize that specifies the number of bytes occupied in memory by this term Term. sizeOfDomain sizeOfDomain : (<domain> Domain) -> integer ByteSize.

Visual Prolog 7.3 Language Reference

Page 132 / 147

Retrieves the number of bytes occupied in memory by the entity of the specified domain DomainName. Call-template for this function is: ByteSize = sizeOfDomain(DomainName) This compiling-time predicate receives the domain DomainName as input parameter and return the size of memory that is occupied by the entity of the given domain. The result is measured in bytes. The returned value ByteSize belongs to the integer domain. Compare with sizeBitsOf/1->, which returns size of a domain measured in bits. sourcefile_lineno sourcefile_lineno : () -> unsigned LineNumber. Returns the current line number in the source file processed by the compiler. sourcefile_name sourcefile_name : () -> string FileName. Returns the name of the source file processed by the compiler. sourcefile_timestamp sourcefile_timestamp : () -> string TimeStamp.. Returns a string that represents the date and time of the currently compiled source file in format YYYY-MM-DD HH:MM:SS. Where:
n n n n n n

YYYY - Year. MM - Month. DD - Day. HH - Hour. MM - Minute. SS - Second.

succeed succeed : (). The predicate succeed/0 will always succeed. toBinary toBinary : (Term) -> binary Serialized. Converts the specified Term to binary representation. Call-template for this function is:

Visual Prolog 7.3 Language Reference

Page 133 / 147

Serialized = toBinary(Term) When a Term (of some domain domainName) is converted into a binary, it can safely be stored in a file or sent over a network to another program. Later the obtained binary value Serialized can be converted back to a Visual Prolog term, using toTerm/1-> function (the domain for the reversed term should be adequate to domainName) for the reverse conversion. toBoolean toBoolean : (<term> SubGoal) -> boolean Succeed. The purpose of this meta-predicate is to convert the deterministic call (to a predicate or fact) to the procedure that returns the value of boolean domain. Call-template for this meta-predicate is: True_or_False = toBoolean(deterministic_call) The toBoolean/1-> meta-predicate returns boolean value. The result is true if deterministic_call succeeds. The result is false if deterministic_call fails. toString toString : (Term) -> string Serialized. Converts the specified Term to string representation. Call-template for this function is: Serialized = toString(Term) When a Term (of some domain domainName) is converted into a string, it can safely be stored in a file or sent over a network to another program. Later the obtained string value can be converted back to a Visual Prolog term, using toTerm/1-> function (the domain of the return value should be adequate to domainName) for the reverse conversion. toTerm toTerm toTerm toTerm toTerm : : : : (string Serialized) -> Term. (binary Serialized) -> Term. (<domain> Type, string Serialized) -> Term. (<domain> Type, binary Serialized) -> Term.

Converts the string/binary representation of the specified term Serialized into representation corresponding to the domain of Term variable of the return value. The domain can be stated explicitly or it can be left to the compiler to determine a suitable domain. Call-template for this function is: Term = toTerm(Serialized) % with implicit domain Term = toTerm(domainName, Serialized) % with explicit domain, domainName

Visual Prolog 7.3 Language Reference

Page 134 / 147

If the domain is not specified the compiler must be able to determine the domain for the returned value Term at compile-time. Notice that binary version of toTerm predicate performs almost byte to byte conversion and only checking general compatibility of Serialized data with the domain required to the return value Term. The programmer is wholly responsible for providing binary data of Serialized that can be correctly converted to the term of the desired domain. The toTerm predicates are counterparts to predicates toBinary/1-> and toString/1->. When a Term (of some domain domainName) is converted into a binary or string representation Serialized (by toBinary/1-> or toString/1-> correspondingly), it can safely be stored in a file or sent over a network to another program. Later the corresponding toTerm/1-> function can convert the obtained string/binary value Serialized back to a Visual Prolog term Term. For correctness of the reverse conversion the domain of the clause variable Term should be adequate to the initial domain domainName. See also tryToTerm. It gives a compile time error if the compiler cannot determine the return domain. Exceptions
n

Run time errors are generated when the toTerm predicate cannot convert the string or binary into a term of the specified domain.

tryToTerm tryToTerm tryToTerm tryToTerm tryToTerm : : : : (string Serialized) -> Term. (binary Serialized) -> Term. (<domain> Type, string Serialized) -> Term. (<domain> Type, binary Serialized) -> Term.

Converts the string/binary representation Serialized into a term Term like toTerm. The only difference between the predicates is that tryToTerm fails if it cannot convert the string or binary into a term of the specified domain whereas toTerm raises an exception. See also toTerm. tryConvert tryConvert : (<type> Type, Value) -> <type> Converted determ. Checks whether the input term InputTerm can be strictly converted into the specified domain Type and returns the converted term Converted. Call-template for this function is: ReturnTerm = tryConvert(returnDomain, InputTerm) Arguments:
n

returnDomain: Specifies a domain to which tryConvert/2-> predicate tries to convert the specified InputTerm. Here returnDomain can be any domain accessible in the current scope. The domain name returnDomain must be specified at compile-time, i.e. it cannot come from a variable. InputTerm: Specifies the term that must be converted. InputTerm may be any Prolog term or an expression. If InputTerm is an expression, then it will be evaluated before conversion. ReturnTerm: Returned term ReturnTerm will be of returnDomain domain.

The conversion rules are the same as of the embedded predicate convert/2->, but tryConvert/2-> fails when convert/2-> generates conversion errors.

Visual Prolog 7.3 Language Reference

Page 135 / 147

This predicate succeeds if the corresponding conversion succeeds. Otherwise it fails. The tryConvert/2-> predicate tries to perform a clean and genuine conversion of the given InputTerm into a value of the specified domain returnDomain. The tryConvert/2-> predicate will fail if the required conversion cannot be performed. When tryConvert/2-> predicate succeeds, it returns the term ReturnTerm converted to the specified domain returnDomain. For allowed conversions and rules of checked explicit conversions see convert/2-> predicate. See also uncheckedConvert/2->. uncheckedConvert uncheckedConvert : (<type> Type, Value) -> <type> Converted. Unchecked conversion of a value to another type. Call-template for this function is: ReturnTerm = uncheckedConvert(returnDomain, InputTerm) Arguments:
n

returnDomain: Specifies a domain to which uncheckedConvert predicate unsafely converts the specified InputTerm. Here returnDomain can be any domain accessible in the current scope, the ReturnTerm should has the same bit-size as the InputTerm. The domain name returnDomain must be specified at compile-time, i.e. it cannot come from a variable. InputTerm: Specifies the value that must be converted. InputTerm may be any Prolog term or an expression. If InputTerm is an expression, then it will be evaluated before conversion. ReturnTerm: Returned parameter ReturnTerm will be of returnDomain type.

uncheckedConvert performs preliminary evaluation of InputTerm (if it is an expression), change current type to returnDomain type and unifies with ReturnTerm. The uncheckedConvert predicate performs no runtime checks. It makes only compile time checking of bit-size equality of the converted domains. So almost any term may be quite recklessly converted to any other term. So quite disastrous results may occur if you try to use variables incorrectly converted by uncheckedConvert. Be extremely careful implementing uncheckedConvert; we strongly recommend you always, when it is possible, using of convert/2-> and tryConvert/2->. But notice that, when an object is returned by COM system it is necessary to convert it by uncheckedConvert, as Prolog program does not have information about its actual type. upperBound upperBound : (<numeric-domain> NumericDomain) -> <number-domain> UpperBound. Returns the upper bound value of the specified numeric domain. Call-template for this function is: UpperBound = upperBound(domainName) The upperBound is a compiling-time predicate. The upperBound returns the upper bound value of the specified numeric domain domainName. The return value UpperBound belongs to the same domain domainName. The domainName parameter should be the name of any numerical domain; this domain name should be explicitly specified at compile-time (that is, domainName cannot come from a variable).

Visual Prolog 7.3 Language Reference

Page 136 / 147

See also lowerBound/1->. Will cause a compile time error if the specified domain domainName is not numeric domain.

Visual Prolog 7.3 Language Reference

Page 137 / 147

Directives
Each compiler directive starts from the # character. The following directives are supported:
n n n n n

#include, #bininclude - file inclusion. #if, #then, #else, #elseif, #endif - conditional statements. #export, #externally - exporting and importing classes. #message, #error, #requires, #orrequires - compilation time information. #options - compiler options.

Source File Inclusion


The #include compiler directive is used to include the contents of another file into your program source code during compilation. It has the following syntax: Pp_dir_include : #include String_literal The string_literal should specify an existing filename. This filename can include a path name, but you must remember that the backslash character \ used to give subdirectories is an escape character. Because of this, you must give two backslash characters \\ when you use the backslash in a path that is written directly into the source text: #include"pfc\\exception\\exception.ph"%Includespfc\exception\exception.phfile or prefix the filename with the @ character, like this #include@"pfc\vpi\vpimessage\vpimessage.ph"%Includespfc\vpi\vpimessage\vpimessage.ph This compiler directive uses "include the first file occurrence only" semantics. That is, if a compilation unit contains several include directives for the same file, it will be included only one time with the first include directive. Each included file must contain several accomplished scopes; an included file cannot contain uncompleted scopes. That is, it should contain several accomplished interface declarations, class declarations, class implementations or/and several compiler directives. The compiler tries to find the specified include source file in the following way: 1. If the filename contains an absolute path, then this file should be included. 2. Otherwise, the compiler searches for the specified include filename among the paths that had been defined by the /Include command line option. These paths are handled consequently as they are specified in the option. In the VDE you can set these paths in the Include Directories in the Directories tab of the Project Settings dialog. If the compiler does not find the specified file a compiling time error is generated.

Binary File Inclusion


The #bininclude compiler directive is used to include (during compilation) the contents of a file (specified by the string_literalstring)asa::binary type constant into your program source code. It has the following syntax:

Visual Prolog 7.3 Language Reference

Page 138 / 147

Pp_dir_bininclude : #bininclude ( String_literal ) The #bininclude compiler directive instructs the compiler to insert the contents of the specified file asthevalueofa::binaryconstant.Thisdirectivecanbeusedinanyplaceswhere::binary constants are allowed. The typical usage is like this: constants myBin : ::binary = #bininclude ("Bin.bin"). % Creates value of binary % constant from "Bin.bin" file myBin2 = #bininclude ("Bin2.bin"). % Short format of a binary % constant initialization In this example. Parsing the first constant myBin declaration, the compiler meets the #bininclude ("Bin.bin") directive. It checks whether the "Bin.bin" file exists in the directory where the source file containing this #bininclude ("Bin.bin") directive is placed or whether the "Bin.bin" file exists in one of directories specified in the Include Directories list box in the Project Settings dialog (in directories defined by the /Include command line option). If the compiler finds the "Bin.bin" file, thenitreadsit.Fromthefilecontentsthecompilerformscorrectdataofthe::binary domain and place it as the myBin constant value. For example, if the "Bin.bin" file contains only one A character, then the myBin constant obtains the following value: myBin = $[0x41] % Here 0x41 is the hexadecimal ASCII value of 'A' The string_literal should specify an existing filename. The syntax is the same as in the #include compiler directive described in the previous paragraph Source File Inclusions. The compiler tries to find the specified file in the same way as for #include compiler directive.

Exporting and Importing Classes


Compiler directives #export and #externally are used to determine lists of exported and imported classes, respectively. They have the following syntax: Pp_dir_export : #export ClassNames-comma-sep-list Pp_dir_export : #externally ClassNames-comma-sep-list These compiler directives are applied only to classes classNames, which do not construct objects. They can be used only outside scopes; that is, they cannot be used inside declarations of interfaces and classes and they cannot be used inside implementations of classes. By default, predicates within one executed module are hidden at runtime for all other executed modules. An #export compiler directive makes names of specified classes public outside the module in which they are declared (and implemented). Therefore, all predicates from this module declared in the classes (specified in an #export directive) become accessible while runtime from other executed modules. Usually, an #export compiler directives can be used in projects, which target modules are DLLs. It enumerates classes declared in a DLL, which should be accessible to other modules that use this DLL. If a compilation unit export some class, then this compilation unit should contain this class implementation.

Visual Prolog 7.3 Language Reference

Page 139 / 147

Also an #export compiler directives can be used to specify condition expressions for #if compiler directives. For example, let us suppose that somewhere in the beginning of a compilation unit the compiler has met the #export compiler directive like this: #export className Then the compiler, if in the subsequent code it meets an #if compiler directive with the same #export compiler directive used as the condition expression, for example like this: #if #export className #then ... #endif Then the compiler evaluates the #export condition expression as true and, hence, the compiler executes the #then branch of the conditional compilation directive. For example, the following #export compiler directive with the subsequent #if conditional compilation compiler directive: #export className ... #if #export className #then #requires "some.pack" #endif guaranty that the "some.pack" package will be included into the compilation unit. From the other hand, if an #export compiler directive is not met by the compiler (somewhere in the compilation unit before the #if compiler directive, which uses the same #export compiler directive as the conditional expression), then the compiler evaluates this #export condition expression as false. Hence, the compiler will not execute the #then branch of the #if conditional compilation directive. That is, the single #if compiler directive without previous #export directive #if #export className #then #requires "some.pack" #endif does not requires to include the "some.pack" package. An #externally compiler directive is counterpart to an #export compiler directive. An #externally compiler directive can be used instead of (and concurrently with) an IMPORTS directive in definition files. An #externally compiler directive enumerates classes, which are declared in a module but implemented in other modules. Therefore, the compiler will not produce errors when it detects such classes. The referenced classes can be implemented (and exported) in DLLs, which can be linked to the module at runtime. The #export and #externally compiler directives can be used as Condition boolean expressions in Conditional Directives. For example, like this: #if #export className #then #include "Some package.pack" #endif

Compile Time Information


Compiler directives #message, #requires, #orrequires, and #error can be used to issue userdefined messages into a listing file while compilation of project modules and to interrupt compilation.

Visual Prolog 7.3 Language Reference

Page 140 / 147

These directives can be used either outside scopes (interface declaration, class declaration or class implementation), or inside scopes but outside sections. They have the following syntax: Pp_dir_message: one of #message String_literal #error String_literal #requires String_literal Pp_dir_orrequires-list-opt #orrequires String_literal When the compiler meets any of these directives, it generates the correspondent warning message and place the directive text into a listing file. A listing file name can be specified with the compiler directive: /listingfile:"FileName" Notice that no empty spaces can be used between the colon : (after /listinglile) and "FileName". By default the compiler does NOT generate informative messages for the #message, #requires, and #orrequires directives. You can switch generation of these informative messages ON specifying the compiler options: /listing:message /listing:requires /listing:ALL Example In this case, when the compiler meets a directive like: #message "Some message" it will place the following text into the listing file: C:\Tests\test\test.pro(14,10):informationc062:#message"Somemessage" The directive #requires (#orrequires) issues arbitrary user-defined messages about the needed source (object) files into a listing file. The #orrequires directive cannot be used alone: the #requires directive should immediately (separated with white spaces or comments only) precede it. The directive #error always terminates the compilation and issues the user-defined error message like the following into a listing file: C:\Tests\test\test.pro(14,10):errorc080:#error"Compilationisinterrupted" You can parse and analyze these messages and accept the required actions. For example, the VDE analyzes information printed by the #requires and #orrequires directives and automatically adds all needed PFC packages and standard libraries to the compiled project (See also the Handling Project Modules topic). Example The directives #requires and #orrequires can be used like this:

Visual Prolog 7.3 Language Reference

Page 141 / 147

#requires @"\Common\Sources\CommonTypes.pack" #orrequires @"\Common\Lib\CommonTypes.lib" #orrequires @"\Common\Obj\Foreign.obj" #if someClass::debugLevel > 0 #then #requires @"\Sources\Debug\Tools.pack" #orrequires @"\Lib\Debug\Tools.lib" #else #requires @"\Sources\Release\Tools.pack" #orrequires @"\Lib\Release\Tools.lib" #endif #orrequires "SomeLibrary.lib" #requires "SomePackage.pack" #if someClass::debugLevel > 0 #then #orrequires @"\Debug\SomePackage.lib" #else #orrequires @"\Release\SomePackage.lib" #endif Example The #message directive can be used like this: #message "Some text" #if someClass::someConstant > 0 #then #message "someClass::someConstant > 0" #else #message "someClass::someConstant <= 0" #endif class someClass #if ::compiler_version > 600 #then #message "New compiler" constants someConstant = 1. #else #message "Old compiler" constants someConstant = 0. #endif end class someClass Example The #error can be used like this: #if someClass::debugLevel > 0 #then #error "Debug version is not yet implemented" #endif

Compiler options directive


Compiler directive #options <string_literal> affects the whole compilation unit. This directive should be used outside scopes and conditional compilation statements in the main source file for a compilation unit (i.e. in the source file which is passed to the compiler). Otherwise the compiler generates a warning message and ignores the directive. The <string_literal> can only contain the following compiler options: "/Warning" "/Check" "/NOCheck" "/Optimize" "/DEBug" "/GOAL" "/MAXErrors" "/MAXWarnings"

Visual Prolog 7.3 Language Reference

Page 142 / 147

Otherwise the compiler generates the error message for invalid option. If there are several #options directives they are handled in the textual order.

Conditional Compilation
The conditional programming constructions are part of the Visual Prolog language. Only other compiler directives, Compilation Units, and program sections (including empty) can be conditional. The following syntax is used: ConditionalItem : #if Condition #then CompilationItem-list-opt ElseIfItem-list-opt ElseItem-opt #endif

ElseIfItem : #elseif Condition #then CompilationItem

ElseItem : #else CompilationItem Here Condition can be any expression, which can be evaluated to fail or succeed during compilation time. Each one conditional compilation statement must be in one file, that is, the compiler directives #if, #then, #elseif and #else (if present), #endif of the same level of nesting must be in one file. During compilation the compiler evaluates the conditions, in order to determine which parts to include in the final program. Parts that are excluded from the final program are called the dead branches. All branches of conditional compilation items are syntax checked and must be syntactically correct. That is, also the dead branches must be syntactically correct. The compiler only calculates conditions on a need to know basis, i.e. it does not calculate conditions in dead branches. A condition may not depend on any code, which is located textually inside the conditional statement. The example below is illegal because the condition depends on the scope (and constant) which is declared inside the condition branch. #if aaa::x > 7 #then % ERROR! class aaa constants x =3 end class aaa #else class aaa constants x = 23 end class aaa #endif

Visual Prolog 7.3 Language Reference

Page 143 / 147

Attributes
Various definitions and declarations can be annotated with attributes. This section describes the general syntax of attributes and where they can be placed. It also describes the meaning of the specific attributes.

Syntax
Attributes : [ Attribute-comma-sep-list ]

Attribute : one of LowerCaseIdentifier LowerCaseIdentifier ( Literal-comma-sep-list ) where the literals must either be numbers or string literals.

Insertion Points
The attributes of interfaces, classes and implementations are right before the scope qualifications. InterfaceDeclaration : interface IinterfaceName Attributes-opt ScopeQualifications Sections end interface IinterfaceName

ClassDeclaration : class ClassName ConstructionType-opt Attributes-opt ScopeQualifications Sections end class ClassName

ClassImplementation : implement ClassName Attributes-opt ScopeQualifications Sections end implement ClassName-opt The attributes of constants, domains, predicates, properties and facts are at the end (i.e. right before the terminating dot). ConstantDefinition: one of ConstantName = ConstantValue Attributes-opt ConstantName : TypeName = ConstantValue Attributes-opt

DomainDefinition: DomainName FormalTypeParameterList-opt = TypeExpression Attributes-opt

PredicateDeclaration : PredicateName : PredicateDomain LinkName-opt Attributes-opt PredicateName : PredicateDomainName LinkName-opt Attributes-opt

PropertyDeclaration : PropertyName : PropertyType FlowPattern-list-opt Attributes-opt

FactDeclaration : FactVariableDeclaration Attributes-opt FactFunctorDeclaration Attributes-opt


Visual Prolog 7.3 Language Reference Page 144 / 147

The attributes of formal arguments are at the end. FormalArgument : TypeExpression ArgumentName-opt Attributes-opt

Specific Attributes
byVal An argument is transferred directly on the stack rather than using a pointer. Valid for formal predicate arguments provided the language is stdcall, apicall or c. Example predicates externalP : (point Point [byVal]) language apicall. deprecated The declared entity is deprecated. The string literal describes how to migrate from it. The entity still exist, but usage will cause a warning. The entity will not exist in future versions of Visual Prolog. Valid for member declarations and scopes. Example predicates oldFasioned : (string Arg) [deprecated("Use newFasion instead")]. formatString The argument is a format string for a subsequent ellipsis argument (i.e. ...). Valid for one string argument of a predicate with an ellipsis argument. The use of formatString will make the compiler check the validity of actual arguments with respect to actual format strings (where possible). Example predicates writef : (string Format [formatString], ...). in The argument is an input argument. Valid for a formal predicate argument. Example predicates pred : (string InputArg [in]). inline inline alters the memory layout of a struct (i.e. a single alternative functor domain with an align qualification). The corresponding field is inlined instead of being pointed to.
Visual Prolog 7.3 Language Reference Page 145 / 147

Example domains point = align 4 p(integer X, integer Y). domains rectangle = align 4 r( point UpperLeft [inline], point LowerRight [inline] ).

It is also possible to inline fixed size string and string8 fields in structs: Example domains device = align 4 device( integer Id, string DeviceName [inline(32)] ). noDefaultConstructor Used for a class to indicate that it should not have an implicit default constructor, and can thus be used to a class that does not have any constructors at all. Valid for an object creating class declaration. Example class classWithoutPublicConstructors : myInterface [noDefaultConstructor] ... end class classWithoutPublicConstructors out The argument is an output argument. Valid for a formal predicate argument. Example predicates pred : (string OutputArg [out]). retired The declared entity is retired. The string literal describes how to migrate from it. The entity does not exist anymore. Example predicates veryOldFasioned : (string Arg) [retired("Use newFasion instead")].

Visual Prolog 7.3 Language Reference

Page 146 / 147

union Used for creating functor domains with several alternatives but no real functors. This should only be used to mimic C/C++ union structs in low-level interfacing. Valid for functor domain with several alternatives and alignment. Example domains u64var = align 4 u64(unsigned64 Value64); u64_struct(unsigned Low32, unsigned High32) [union]. used An unused local member can be marked used to prevent the compiler to issue a warning and remove the corresponding code. Valid for local members. Example predicates seeminglyUnused : () [used].

Visual Prolog 7.3 Language Reference

Page 147 / 147

Vous aimerez peut-être aussi