Difference between revisions of "Language Reference/Predicates"

From wiki.visual-prolog.com
(programPoint)
(→‎Suspending: Released)
 
(20 intermediate revisions by 2 users not shown)
Line 7: Line 7:
<vipbnf><PredicatesSection> :
<vipbnf><PredicatesSection> :
   class-opt predicates <PredicateDeclaration>-dot-term-list-opt</vipbnf>
   class-opt predicates <PredicateDeclaration>-dot-term-list-opt</vipbnf>
The keyword <vp>class</vp> 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 <vp>class</vp> can be used only inside class implementations, since:
The keyword <vp>class</vp> can be used only inside class implementations, since:
Line 28: Line 26:
   <LowerCaseIdentifier></vipbnf>
   <LowerCaseIdentifier></vipbnf>


Here {{lang2|Domains|Predicate Domains|predicateDomainName}} is the name of a predicate domain declared in the domains section.
Here {{lang2|Predicates|Predicate Domains|PredicateDomainName}} is the name of a predicate domain declared in a domains section.
 
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 {{lang2|Predicates|Calling Convention|calling convention}}.
 
=== Predicate Domains ===
 
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.
 
<vipbnf><PredicateDomain>:
  ( <FormalArgument>-comma-sep-list-opt ) <ReturnArgument>-opt
  <PredicateModeAndFlow>-list-opt <CallingConvention>-opt</vipbnf>
 
<vipbnf><FormalArgument>:
  <TypeExpression> <VariableName>-opt
  <Ellipsis></vipbnf>
<vipbnf><ReturnArgument>:
    -> <FormalArgument></vipbnf>
<vipbnf><VariableName>:
  <UpperCaseIdentifier></vipbnf>
Predicate domains can have <vpbnf><Ellipsis></vpbnf> argument as the last <vpbnf><FormalArgument></vpbnf> in the <vpbnf><FormalArgument>-comma-sep-list</vpbnf>.
Predicate domains can have an <vpbnf><AnonymousIdentifier></vpbnf> as a formal argument type to specify that the argument can be of any type.
<vipbnf><PredicateModeAndFlow>:
    <PredicateMode>-opt
    <Suspending>-opt
    <FlowPattern>-list-opt</vipbnf>
 
==== Predicate Mode ====
 
The specified predicate mode applies for each member of a flow pattern list following it.
 
<vipbnf><PredicateMode>: one of
  erroneous
  failure
  procedure
  determ
  multi
  nondeterm</vipbnf>
 
Predicate modes can be described by the following sets:
 
<vip>erroneous = {}
failure = {Fail}
procedure = {Succeed}
determ = {Fail, Succeed}
multi = {Succeed, BacktrackPoint}
nondeterm = {Fail, Succeed, BacktrackPoint}</vip>
 
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 <vp>failure</vp>, is a subset of another set, say <vp>nondeterm</vp>, then we say that the mode is stronger than the other, i.e. <vp>failure</vp> is stronger than <vp>nondeterm</vp>.
 
 
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 <vp>procedure</vp> mode.
 
Omitting of a predicate mode means <vp>procedure</vp>.
 
==== Suspending ====
 
Adding <vp>suspending</vp> to a predicate domain makes the predicate a {{lang|Suspending Predicates|suspending predicate}}
 
<vipbnf><Suspending>:
  suspending</vipbnf>
 
==== 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).
 
<vipbnf><FlowPattern>:
    ( <Flow>-comma-sep-list-opt ) AnyFlow</vipbnf>
 
<vipbnf><Flow>: one of
    i
    o
    <FunctorFlow>
    <ListFlow>
    <Ellipsis></vipbnf>
 
Ellipsis flow must match an ellipsis argument and can therefore be only the last flow in the flow pattern.
 
<vipbnf><Ellipsis>:
    ...</vipbnf>
 
A functor flow <vpbnf><FunctorFlow></vpbnf> 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.
 
<vipbnf><FunctorFlow>:
    <FunctorName> ( <Flow>-comma-sep-list-opt )</vipbnf>
 
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.
 
<vipbnf><ListFlow>:
    [ <Flow>-comma-sep-list-opt <ListFlowTail>-opt]</vipbnf>
 
<vipbnf><ListFlowTail>:
    | <Flow></vipbnf>
 
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.
 
The special flow pattern <vp>anyflow</vp> 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(s) will be evaluated during the compilation.
 
{{Example|
<vip>domains
    pp1 = (integer Argument1).</vip>
 
<vp>pp1</vp> is a predicate domain. The predicates that have type <vp>pp1</vp> takes one {{lang2|Built-in_entities|integer|integer}} argument. Since no flow-pattern is stated the argument is input, and since no predicate mode is mentioned the predicates are <vp>procedure</vp>.
}}
 
{{Example|
<vip>domains
    pp2 = (integer Argument1) -> integer ReturnType.</vip>
 
Predicates of type <vp>pp2</vp> take one {{lang2|Built-in_entities|integer|integer}} argument and returns a value of type {{lang2|Built-in_entities|integer|integer}}. Therefore, <vp>pp2</vp> is actually a function domain and the predicates that have type <vp>pp2</vp> are actually functions. Since no flow-pattern is stated the argument is input and since no predicate mode is mentioned the predicates are <vp>procedure</vp>.
}}
 
{{Example|
<vip>predicates
    ppp : (integer Argument1, integer Argument2) determ (o,i) (i,o) nondeterm (o,o).</vip>
 
The predicate <vp>ppp</vp> takes two {{lang2|Built-in_entities|integer|integer}} arguments. It exists in three flow variants: <vp>(o,i)</vp> and <vp>(i,o)</vp>, which are <vp>determ</vp>, and <vp>(o,o)</vp>, which is <vp>nondeterm</vp>.
}}
 
==== 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.
 
<vipbnf><CallingConvention>:
    language <CallingConventionKind></vipbnf>
 
<vipbnf><CallingConventionKind>: one of
    c thiscall stdcall apicall prolog</vipbnf>
 
If a calling convention is not stated, then the <vp>prolog</vp> convention is assumed. The <vp>prolog</vp> calling convention is the standard convention used for Prolog predicates.
 
The calling convention <vp>c</vp> follows the C/C++ standard calling convention. The link name of a predicate is created from the predicate name by adding a leading underscore (<vp>_</vp>).
 
The calling convention <vp>thiscall</vp> follows the C++ standard calling convention for virtual functions. This calling convention uses the <vp>c</vp> link name strategy but sometimes it may use the different argument and stack handling rules. Calling convention <vp>thiscall</vp> can be applied to the object predicates only.
 
The calling convention <vp>stdcall</vp> uses the <vp>c</vp> link name strategy but it uses the different argument and stack handling rules. The following table shows the implementation of <vp>stdcall</vp> calling convention.
 
 
 
{|{{prettytable}}
|-
!Feature
!Implementation
|-
|Argument-passing order
|Right to left.
|-
|Argument-passing convention
|By value, unless a compound domain term is passed. So it cannot be used to predicates with variable number of arguments.
|-
|Stack-maintenance responsibility
|Called predicate pops its own arguments from the stack.
|-
|Name-decoration convention
|An underscore (<vp>_</vp>) is prefixed to the predicate name.
|-
|Case-translation convention
|No case translation of the predicate name is performed.
|}
 
 
The calling convention <vp>apicall</vp> uses the same argument and stack handling rules as <vp>stdcall</vp>, but for convenience to call MS Windows API functions <vp>apicall</vp> uses the naming conventions that are used by most MS Windows API functions. According to <vp>apicall</vp> naming conventions the link name of a predicate is constructed as follows:
 
*a leading underscore (<vp>_</vp>) is prefixed to the predicate name;
*the predicate name in which the first letter is changed in to a capital letter;
*the '<vp>A</vp>', the '<vp>W</vp>' or nothing is suffixed, if the arguments and the return type indicate an ANSI, Unicode or neutral predicate, respectively;
*on the 32bit platform (x86) the sign <vp>@</vp> together with the number of bytes in the argument list is suffixed.  But this is not used on the 64bit platform.
 
{{Example|
<vip>predicates
    predicateName : (integer, string) language apicall</vip>
 
The argument types of this predicate indicates that it is a Unicode predicate (as {{lang2|Built-in_entities|string|string}} is the domain of Unicode strings). An {{lang2|Built-in_entities|integer|integer}} and a {{lang2|Built-in_entities|string|string}} each occupies 4 bytes on the call stack and, therefore, the link name becomes:
 
<source lang="text">_PredicateNameW@8</source>
 
On x64 the name is:
<source lang="text">_PredicateNameW</source>
}}
 
If <vp>apicall</vp> is used together with the "<vp>as</vp>" construction the name stated in the "<vp>as</vp>" construction is decorated in the same manner.
 
<vp>apicall</vp> can only be used directly in a predicate declaration, not in a predicate domain definition. In predicate domain definitions <vp>stdcall</vp>, must be used instead. A predicate declared with <vp>apicall</vp> calling convention cannot have clauses and it also cannot be resolved externally without explicit DLL name.
 
The following table compares implementations of <vp>c</vp>, <vp>apicall</vp>, and <vp>stdcall</vp> calling conventions (the <vp>prolog</vp> calling convention has the special implementation, which is not discussed here):
 
{|{{prettytable}}
|-
!Keyword
!Stack cleanup
!Predicate name case-translation
!Link predicate name decoration convention
|-
|<vp>c</vp>
|'''Calling''' predicate pops the arguments from the stack.
|None.
|An underscore (<vp>_</vp>) is prefixed to the predicate name.
|-
|<vp>thiscall</vp>
|'''Calling''' predicate pops the arguments from the stack except the implicit '''This''' argument which is passed in the register.
|None.
|<vp>c</vp> link name strategy is used.
|-
|<vp>stdcall</vp>
|'''Called''' predicate pops its own arguments from the stack.
|None.
|An underscore (<vp>_</vp>) is prefixed to the predicate name.
|-
|<vp>apicall</vp>
|'''Called''' predicate pops its own arguments from the stack.
|The first letter of the predicate name is changed to the capital letter.
|An underscore (<vp>_</vp>) is prefixed to the name. The first letter is changed to the upper case. The '<vp>A</vp>', the '<vp>W</vp>' or nothing is suffixed. And on the 32bit platform (x86) the sign <vp>@</vp> together with the number of 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:
 
<vip>interface actionEventSource
domains
    actionListener = (actionEventSource Source) procedure (i).
predicates
    addActionListener : (actionListener Listener) procedure (i).
    ... end interface</vip>


A predicate declaration states the name of the predicate, its type, mode, flow (see {{lang2|Domains|Flow Pattern|predicate domains}}), and optionally a {{lang2|Domains|Calling Convention|link name}}.
Also assume a class <vp>button_class</vp> which supports the <vp>actionEventSource</vp>. The event is sent when the button is pressed. In <vp>myDialog_class</vp> 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:


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.
<vip>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</vip>


If the calling convention is {{lang2|Domains|Calling Convention|apicall}} then the link name stated in the <vp>as</vp> clause is decorated anyway. If this decoration is unintended, use {{lang2|Domains|Calling Convention|stdcall}} instead.
The important thing about the example is that <vp>onOk</vp> is an object member and that, when the button is pressed, the invocation of the registered <vp>onOk</vp> will bring us back in the object that owns <vp>onOk</vp>. This means that we have access to the object fact <vp>okPressed</vp>, so that we can assert it.
}}


==== Decorated ====
==== 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:
Sometimes a name must have the <vp>_...@N</vp> decoration, but the default from <vp>apicall</vp> is wrong. In such cases <vp>decorated</vp>, <vp>decoratedA</vp> and <vp>decoratedW</vp> can be used to control the decoration:


<vip>predicates
<vip>predicates
Line 44: Line 294:


In this case the link name will be "<vp>_MyPredicate@4</vp>", where apicall would make it "<vp>_MyPredicate</vp><vpbnf>W</vpbnf><vp>@4</vp>".
In this case the link name will be "<vp>_MyPredicate@4</vp>", where apicall would make it "<vp>_MyPredicate</vp><vpbnf>W</vpbnf><vp>@4</vp>".


<vip>predicates
<vip>predicates
Line 50: Line 299:


In this case the link name will be "<vp>_MyPredicate</vp><vpbnf>A</vpbnf><vp>@4</vp>", where apicall would make it "<vp>_MyPredicate@4</vp>".
In this case the link name will be "<vp>_MyPredicate</vp><vpbnf>A</vpbnf><vp>@4</vp>", where apicall would make it "<vp>_MyPredicate@4</vp>".


<vip>predicates
<vip>predicates
Line 57: Line 305:
In this case the link name will be "<vp>_MyPredicate</vp><vpbnf>W</vpbnf><vp>@4</vp>", where apicall would make it "<vp>_MyPredicate@4</vp>".
In this case the link name will be "<vp>_MyPredicate</vp><vpbnf>W</vpbnf><vp>@4</vp>", where apicall would make it "<vp>_MyPredicate@4</vp>".


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".
All of them change the start of the name from <vp>xxxx</vp> to <vp>_Xxxx</vp> and all of them put <vp>@N</vp> 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 ===
=== Constructors Sections ===


A <vp>constructors</vp> section declares a set of constructors. The constructors belong to the scope in which the <vp>constructors</vp> section occurs (see {{lang2|Classes|Class Declarations|class declaration}} and {{lang2|Implementations|Class Implementations|class implementation}}).
A <vp>constructors</vp> section declares a set of constructors. The constructors belong to the scope in which the <vp>constructors</vp> section occurs (see {{lang|Classes|class declaration}} and {{lang|Implementations|class implementation}}).


<vipbnf><ConstructorsSection> :
<vipbnf><ConstructorsSection> :
Line 178: Line 426:


<vp>aaa_class</vp> can inherit <vp>ppp</vp> from <vp>bbb_class</vp>, because <vp>ppp</vp> in both classes has <vp>aaa</vp> as origin interface.
<vp>aaa_class</vp> can inherit <vp>ppp</vp> from <vp>bbb_class</vp>, because <vp>ppp</vp> in both classes has <vp>aaa</vp> as origin interface.
}}
=== Extension Predicates ===
Extension predicates is a syntactic sugaring, which makes it possible use class predicates as if they were object predicates.
{{Example|A typical use case is for code like this:
<vip>
clauses
    writeMsg(Stream, fct(Receiver, Sender)) :-
        Stream:write("Hello "),
        writeReceiver(Stream, Receiver),
        Stream:write(", how do you do?\nRegards "),
        writeSender(Stream, Sender).
</vip>
This code writes a number of things to <vp>Stream</vp>, but some of the calls are object calls <vp>Stream:write(...)</vp> with the stream in front of a colon, while others are class calls <vp>writeReceiver(Stream, ...)</vp> with the stream as first argument.
Declaring <vp>writeReceiver</vp> and <vp>writeSender</vp> as extension predicates will make all the calls have the same syntactic form:
<vip>
clauses
    writeMsg(Stream, fct(Receiver, Sender)) :-
        Stream:write("Hello "),
        Stream:writeReceiver(Receiver),
        Stream:write(", how do you do?\nRegards "),
        Stream:writeSender(Sender).
</vip>
In this code the predicates <vp>writeReceiver</vp> and <vp>writeSender</vp> seems to be part of the <vp>Stream</vp>s interface.  So they appear to have ''extended'' the <vp>Stream</vp>s interface.
}}
Extension predicates can also be used to give give a more natural code flow for binary operations:
{{Example|(Binary operations
<vip>
class matrix
    add : (matrix A, matrix B) -> matrix R.
    add2 : (matrix A [this], matrix B) -> matrix R.  % extension
clauses
  xxx(A, B, C) = add(add(A, B), C).  % add must be used in front of the operands
clauses
  yyy(A, B, C) A:add2(B):add2(C). % add2 can be written infix
</vip>
You should notice that such infix operations are left associative, if you want <vp>add(A, add(B, C))</vp> you must write: <vp>A:add2(B:add2(C))</vp>.
You should also notice that there is no precedence in this context.
<vip>
A + B * C = A + (B * C) -> A:add2(B:mult2(C))
A:add2(B):mult2(C) -> (A + B) * C
</vip>
}}
Extension predicates can also support a ''cascading data flow'' style:
{{Example|Cascading data flow style:
<vip>
clauses
    getQ(A, X, F) = qqq::new(A):select(12, X, getList()):filter( { (V) :- V = F } ).
</vip>
The created <vp>qqq</vp> object flows into the <vp>select</vp> predicate the result of this flows into the <vp>filter</vp> predicate and the result of this is returned.
Here <vp>select</vp> and <vp>filter</vp> could be regular object predicates declared in an interface, but they can also be extension predicates.
Assuming they are extension predicates then the corresponding code with regular class predicates would/could look like this:
<vip>
clauses
    getQ(A, X, F) = filter(select(qqq::new(A), 12, X, getList()), { (V) :- V = F } ).
</vip>
}}
An extension predicate is a class predicate whose first argument is marked with the attribute <vp>[this]</vp>.
{{Example|If the regular version of the <vp>writeReceiver</vp> and <vp>writeSender</vp> predicates above are declared like this:
<vip>
class predicates
    writeReceiver : (outputStream Stream, receiver Receiver).
    writeSender : (outputStream Stream, sender Sender).
</vip>
Then the corresponding extension predicates are declared like this:
<vip>
class predicates
    writeReceiver : (outputStream Stream [this], receiver Receiver).
    writeSender : (outputStream Stream [this], sender Sender).
</vip>
I.e. the first argument is marked with the attribute <vp>[this]</vp>.
}}
Extension predicates can also be declared for non-object types.
{{Example|We can for example declare a length extension predicate for lists like this:
<vip>
class predicates
    length : (Type* List [this]) -> positive Length.
</vip>
And then we can call it like this:
<vip>
L1 = List:length(),
L2 = [1, 2]:length(),
L3 = Obj:theList:length() + 7,
</vip>
Notice that <vp>:length()</vp> can be put after anything that evaluates to a list.
}}
It is illegal to declare an extension predicate on an interface type if that extension predicate is conflicting with a predicate that exist in the interface itself.
{{Example|Given the interface <vp>aaa</vp> with predicate <vp>ppp/0</vp>:
<vip>
interface aaa
predicates
    ppp : ().
end interface aaa
</vip>
the following extension predicate is illegal:
<vip>
class predicates
    ppp : (aaa A [this]).  % Illegal: aaa already has a ppp/0 predicate
</vip>
}}
Extension predicates follows the visibility rules of class predicates.
{{Example|Given this class
<vip>
class listExt
predicates
    length : (A* List) -> integer Length.
end class listExt
</vip>
This code is illegal
<vip>
implement myClass
clauses
    ppp(L) = L:length(). % length is not visible
end implement myClass
</vip>
opening the <vp>listExt</vp> class makes the predicate visible:
<vip>
implement myClass
    open listExt
clauses
    ppp(L) = L:length(). % length is visible because listExt is opened
end implement myClass
</vip>
}}
Extension predicates can be qualified with namespace and class:
{{Example|Using qualification
<vip>
implement myClass
clauses
    ppp(L) = L:listExt::length(). % length is visible due to the qualification listExt::...
end implement myClass
</vip>
}}
Several suitable extension predicates may be visible in a certain context, and thus cause ambiguity.  Qualification can resolve such ambiguity.
{{Example|Given <vp>listExt::length</vp> above and a similar/identical extension predicate in listExt2:
<vip>
class listExt2
predicates
    length : (A* List) -> integer Length.
end class listExt2
</vip>
The following code have an ambiguous reference to length:
<vip>
implement myClass
    open listExt, listExt2
clauses
    ppp(L) = L:length(). % length is ambiguous because it is visible both in listExt and listExt2
end implement myClass
</vip>
Qualification can be used to resolve the ambiguity:
<vip>
implement myClass
    open listExt, listExt2
clauses
    ppp(L) = L:listExt2::length(). % length is the one from listExt2
end implement myClass
</vip>
}}
}}


Line 203: Line 628:
In ''Name/0...'' and ''Name/0...->.'' the zero is optional and can thus be written as ''Name/...'' and ''Name/...->'', respectively.
In ''Name/0...'' and ''Name/0...->.'' the zero is optional and can thus be written as ''Name/...'' and ''Name/...->'', respectively.


=== programPoint ===
=== See also ===
 
{{Preliminary Documentation}}
 
A <vp>programPoint</vp> is a value that represents a specific point in a clause.  The <vp>programPoint</vp> contains the class name, the predicate name, the source cursor (file, line and character number), the <vp>programPoint</vp> is defined in the <vp>core</vp> class
 
<vp>programPoint</vp>'s are used by the exception mechanism to indicate where exceptions are raised and continued, but the usage is not limited to that purpose.
 
The compiler suppors <vp>programPoint</vp>'s in a spacial way by means of the attribute <vp>programPoint</vp>, which can be added to a predicate declaration like this:
 
<vip>predicates
    raiseAnException : (integer X) [programPoint].</vip>
 
Adding this attribute actually means that two predicates are declared, the one you have mentioned and an anotherone with name <vp>raiseAnException_explicit</vp> which in addition to the arguemnts of <vp>raiseAnException</vp> takes a <vp>programPoint</vp> as first argument:
 
<vip>predicates
    raiseAnException : (integer X).
   
predicates
    raiseAnException_explicit : (programPoint ProgramPoint, integer X).</vip>
 
When you call raiseAnException the compiler will actually create a program point ans call raiseAnException_explicit instead.
{{example|
<vip>clauses
    test() :-
        raiseAnException(17).</vip>
will actually correspond to:
<vip>clauses
    test() :-
        raiseAnException_explicit(programPoint(...), 17).
</vip>
where the program point corresponds to the point where <vp>raiseAnException</vp> is called in the <vp>test</vp> predicate.}}
 
If you have a programPoint you can directly call the explicit predicate with it.
 
{{example|
<vip>clauses
    raiseAnExceptio17_explicit(ProgramPoint) :-
        raiseAnException_explicit(ProgramPoint, 17).
</vip>
Typically, as in this example, explicit predicates will call other explicit predicates with the programPoint they receive in order to use an "original" call point in a nested explicit predicate.}}
 
Such code is treated in the usual way.  I.e. when calling <vp>raiseAnException</vp> or <vp>raiseAnException_explicit</vp> will in both cases result in calling <vp>raiseAnException_explicit</vp>, so this is the only predicate that needs an implementation.  In fact, it is illegal to state clauses for the non-explicit predicate that will never be called.


To summarize:
These attributes are specifically related to predicates
* A predicate declaration with programPoint attribute actually declares two predicates.  A non-explicit and an explicit predicate.
* Calling the non-explicite predicate actually results in calling the explicit predicate with the call point as aditina argument.
* Only the explicit predicate should be implemented.


The introduction of the the programPoint feature simplifies the exception mechanism as known in Visual Prolog 7.3 and before.  For example <vp>classInfo</vp> predicates are no longer needed (though they in Visual Prolog 7.4 are still legal but deprecated to ease transition).
* {{lang2|Attributes|formatString|formatString}} attribute
* {{lang2|Attributes|programPoint|programPoint}} attribute
* {{lang2|Attributes|in|in}}, {{lang2|Attributes|out|out}} and {{lang2|Attributes|byVal|byVal}} attributes

Latest revision as of 13:02, 11 January 2024

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, since:

  • 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 a domains section.

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.

Predicate Domains

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
FormalArgument:
   TypeExpression VariableName-opt
   Ellipsis
ReturnArgument:
    -> FormalArgument
VariableName:
   UpperCaseIdentifier

Predicate domains can have Ellipsis argument as the last FormalArgument in the FormalArgument-comma-sep-list.

Predicate domains can have an AnonymousIdentifier as a formal argument type to specify that the argument can be of any type.

PredicateModeAndFlow:
     PredicateMode-opt
     Suspending-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.


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.

Suspending

Adding suspending to a predicate domain makes the predicate a suspending predicate

Suspending: 
   suspending

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.

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.

The 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(s) will be evaluated during the compilation.

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
CallingConventionKind: one of
     c thiscall 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 thiscall follows the C++ standard calling convention for virtual functions. This calling convention uses the c link name strategy but sometimes it may use the different argument and stack handling rules. Calling convention thiscall can be applied to the object predicates only.

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 Implementation
Argument-passing order Right to left.
Argument-passing convention By value, unless a compound domain term is passed. So it cannot be used to predicates with variable number of arguments.
Stack-maintenance responsibility Called predicate pops its own arguments from the stack.
Name-decoration convention An underscore (_) is prefixed to the predicate name.
Case-translation convention No case translation of the predicate name is performed.


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:

  • a 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;
  • on the 32bit platform (x86) the sign @ together with the number of bytes in the argument list is suffixed. But this is not used on the 64bit platform.
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

On x64 the name is:

_PredicateNameW

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. A predicate declared with apicall calling convention cannot have clauses and it also cannot be resolved externally without explicit DLL name.

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

Keyword Stack cleanup Predicate name case-translation Link predicate name decoration convention
c Calling predicate pops the arguments from the stack. None. An underscore (_) is prefixed to the predicate name.
thiscall Calling predicate pops the arguments from the stack except the implicit This argument which is passed in the register. None. c link name strategy is used.
stdcall Called predicate pops its own arguments from the stack. None. An underscore (_) is prefixed to the predicate name.
apicall Called predicate pops its own arguments from the stack. The first letter of the predicate name is changed to the capital letter. An underscore (_) is prefixed to the name. The first letter is changed to the upper case. The 'A', the 'W' or nothing is suffixed. And on the 32bit platform (x86) the sign @ together with the number of 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.

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:

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:

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

  • 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
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 ccc

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.

Extension Predicates

Extension predicates is a syntactic sugaring, which makes it possible use class predicates as if they were object predicates.

Example A typical use case is for code like this:
clauses
    writeMsg(Stream, fct(Receiver, Sender)) :-
        Stream:write("Hello "),
        writeReceiver(Stream, Receiver),
        Stream:write(", how do you do?\nRegards "),
        writeSender(Stream, Sender).

This code writes a number of things to Stream, but some of the calls are object calls Stream:write(...) with the stream in front of a colon, while others are class calls writeReceiver(Stream, ...) with the stream as first argument.

Declaring writeReceiver and writeSender as extension predicates will make all the calls have the same syntactic form:

clauses
    writeMsg(Stream, fct(Receiver, Sender)) :-
        Stream:write("Hello "),
        Stream:writeReceiver(Receiver),
        Stream:write(", how do you do?\nRegards "),
        Stream:writeSender(Sender).

In this code the predicates writeReceiver and writeSender seems to be part of the Streams interface. So they appear to have extended the Streams interface.

Extension predicates can also be used to give give a more natural code flow for binary operations:

Example (Binary operations
class matrix
    add : (matrix A, matrix B) -> matrix R.
    add2 : (matrix A [this], matrix B) -> matrix R.  % extension
 
clauses
   xxx(A, B, C) = add(add(A, B), C).  % add must be used in front of the operands
clauses
   yyy(A, B, C) A:add2(B):add2(C). % add2 can be written infix

You should notice that such infix operations are left associative, if you want add(A, add(B, C)) you must write: A:add2(B:add2(C)). You should also notice that there is no precedence in this context.

A + B * C = A + (B * C) -> A:add2(B:mult2(C))
A:add2(B):mult2(C) -> (A + B) * C

Extension predicates can also support a cascading data flow style:

Example Cascading data flow style:
clauses
    getQ(A, X, F) = qqq::new(A):select(12, X, getList()):filter( { (V) :- V = F } ).

The created qqq object flows into the select predicate the result of this flows into the filter predicate and the result of this is returned. Here select and filter could be regular object predicates declared in an interface, but they can also be extension predicates. Assuming they are extension predicates then the corresponding code with regular class predicates would/could look like this:

clauses
    getQ(A, X, F) = filter(select(qqq::new(A), 12, X, getList()), { (V) :- V = F } ).

An extension predicate is a class predicate whose first argument is marked with the attribute [this].

Example If the regular version of the writeReceiver and writeSender predicates above are declared like this:
class predicates
    writeReceiver : (outputStream Stream, receiver Receiver).
    writeSender : (outputStream Stream, sender Sender).

Then the corresponding extension predicates are declared like this:

class predicates
    writeReceiver : (outputStream Stream [this], receiver Receiver).
    writeSender : (outputStream Stream [this], sender Sender).

I.e. the first argument is marked with the attribute [this].

Extension predicates can also be declared for non-object types.

Example We can for example declare a length extension predicate for lists like this:
class predicates
    length : (Type* List [this]) -> positive Length.

And then we can call it like this:

L1 = List:length(),
L2 = [1, 2]:length(),
L3 = Obj:theList:length() + 7,

Notice that :length() can be put after anything that evaluates to a list.

It is illegal to declare an extension predicate on an interface type if that extension predicate is conflicting with a predicate that exist in the interface itself.

Example Given the interface aaa with predicate ppp/0:
interface aaa
predicates
    ppp : ().
end interface aaa

the following extension predicate is illegal:

class predicates
    ppp : (aaa A [this]).  % Illegal: aaa already has a ppp/0 predicate

Extension predicates follows the visibility rules of class predicates.

Example Given this class
class listExt
predicates
    length : (A* List) -> integer Length.
end class listExt

This code is illegal

implement myClass
clauses
    ppp(L) = L:length(). % length is not visible
end implement myClass

opening the listExt class makes the predicate visible:

implement myClass
    open listExt
clauses
    ppp(L) = L:length(). % length is visible because listExt is opened
end implement myClass

Extension predicates can be qualified with namespace and class:

Example Using qualification
implement myClass
clauses
    ppp(L) = L:listExt::length(). % length is visible due to the qualification listExt::...
end implement myClass

Several suitable extension predicates may be visible in a certain context, and thus cause ambiguity. Qualification can resolve such ambiguity.

Example Given listExt::length above and a similar/identical extension predicate in listExt2:
class listExt2
predicates
    length : (A* List) -> integer Length.
end class listExt2

The following code have an ambiguous reference to length:

implement myClass
    open listExt, listExt2
clauses
    ppp(L) = L:length(). % length is ambiguous because it is visible both in listExt and listExt2
end implement myClass

Qualification can be used to resolve the ambiguity:

implement myClass
    open listExt, listExt2
clauses
    ppp(L) = L:listExt2::length(). % length is the one from listExt2
end implement myClass

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:

  • Name/N meaning an ordinary predicate (i.e. not a function) Name of arity N.
  • Name/N-> meaning a function Name of arity N.
  • 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.

See also

These attributes are specifically related to predicates