Difference between revisions of "Language Reference/Properties"

From wiki.visual-prolog.com
m (Example Template)
 
(7 intermediate revisions by one other user not shown)
Line 1: Line 1:
{{languageReferenceNavbar|Properties}}
{{languageReferenceNavbar|Properties}}


The properties section declares a set of object or class properties in the current scope.
Properties are named values associated with classes and objects.  Actually they are syntactic sugar for get/set predicates for the property value.  And in that sense they are a language incarnation of a frequently used programming pattern.


=== Declaration ===
=== Properties Sections ===
 
A properties section declares a set of object or class properties in the current scope.
 
<vipbnf><PropertiesSection> :
  class-opt properties <PropertyDeclaration>-dot-term-list-opt</vipbnf>
 
The keyword <vp>class</vp> can be used only inside class implementations, since:
* properties declared in an interface are always object properties and
* properties declared in a class declaration are always class properties.
 
=== Property Declaration ===


<vipbnf><PropertyDeclaration> :
<vipbnf><PropertyDeclaration> :
     <PropertyName> : <PropertyType> <FlowPattern>-list-opt.
     <PropertyName> : <PropertyType> <FlowPattern>-list-opt</vipbnf>


<FlowPattern>: one of
<vipbnf><FlowPattern>: one of
     (i)
     (i)
     (o)</vipbnf>
     (o)</vipbnf>


The properties are declared similar to single facts.  
It is possible to get the value of a property that has the (o) flow, and it is possible to set the value of a property that has the (i) flow. 
If the flow patterns are not stated, both (i) and (o) are assumed, so it is possible bot to set and get the value of such properties.


If flow patterns are skipped, both (i) and (o) are assumed.
Though it is legal to state (i) and (o) simultaneously, it is considered better practice to omit them in the get+set case.


For example:
{{example|Assume we declare them with an i/o pattern as:
<vip>properties
    durationO : real (o). % a get only property
    durationI : real (i). % a set only property
    durationIO : real (i) (o). % a "full" property, which can both be set and get.
    duration : real. % equivalent to the declaration above and preferred.</vip>}}


<vip>interface ip
In the sequel we will use the use the following example:
 
{{example|<vip>interface ip
properties
properties
   duration : integer.
   duration : real.
   initialized : boolean.
   initialized : boolean (o).
   scale : string.
   scale : real.
end interface</vip>
end interface</vip>
<vp>duration</vp> and <vp>scale</vp> are get+set properties, and <vp>initialized</vp> is a get-only property.}}


The properties are used exactly like single facts inside the implementation. It is possible to qualify properties for a scope name or object.
Properties are used like fact variables. It is possible to qualify properties for with a scope name or an object.


<vp>X</vp> is an object that supports the interface ip
{{example|<vp>X</vp> is an object that supports the interface <vp>ip</vp>


<vip>X:duration := 5,
<vip>X:duration := 5,
if X:initialized = true then ... else ... end if,
if true = X:initialized then ... else ... end if,
X:scale := "meter",
X:scale := 2.56,
....</vip>
....</vip>


Inside an implementation of ip you access the properties as if they were facts.
Inside an implementation of a class that supports <vp>ip</vp> you access the properties as if they were facts.


<vip>duration := 5,
<vip>duration := 5,
if initialized = true then ... else ... end if,
if true = initialized then ... else ... end if,
scale := "meter",
scale := 2.56,
....</vip>
....</vip>}}


=== Implementation ===
=== Implementation ===


You implement a property by defining a function for getting the value and an appropriate predicate to set it.
A property is implemented by defining a function for getting the value and a predicate to set it.


E.g.,
{{example|
<vip>clauses
    % implementation of the get function of the duration property
    duration() = duration_fact.


<vip>clauses
clauses
     duration() = duration_fact * scale.
     % implementation of the set predicate of the duration property
     duration(D):- duration_fact := D/ scale.</vip>
     duration(D) :-
        duration_fact := D / scale.</vip>}}


Or as a fact with the same name as the property
Alternatively the property can be implemented as a fact variable with the same name as the property.


{{example|
<vip>facts
<vip>facts
     initialized : boolean := false.</vip>
    % the initialized property is implemented by a fact variable
     initialized : boolean := false.
    % the scale property is implemented by a fact variable
    scale : real := 1.2</vip>}}
 
In this case the compiler will implicitly provide clauses that implement the get and set predicates.
 
{{example|For the two fact variable implementations above the compiler will provide clauses corresponding to this
<vip>
clauses
    % implicit get clause for the initialized property
    initialized() = initialized.
 
clauses
    % implicit get clause for the scale property
    scale() = scale.


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.:
clauses
    % implicit set clause for the scale property
    scale(V) :-
        scale := V.
</vip>
As mentioned below it would not be legal to state these clauses in a program.}}


It is illegal to have set and get predicates and a fact with the same name, meaning that a property is either implemented by programmer provided clauses or by a fact; mixed implementation is not possible.
{{example|We want to send a '''changed''' event when the <vp>duration</vp> property changes value.  Therefore we have to implement the property by predicates, and use a fact variable with an other name for storing the value.
<vip>properties
<vip>properties
     duration : integer.
     duration : integer.
Line 72: Line 120:
         sendChanged().
         sendChanged().
     duration(_D).</vip>
     duration(_D).</vip>
It is not possible to use the <vp>duration</vp> predicates as predicates (they are not declared as predicates, but as a property; it is just the way the get and set of the property are implemented).


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 "used" - so you cannot declare predicates <vp>duration\1</vp> or <vp>duration\0-></vp>.}}
 
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:
<vip>duration : integer (o).    % a read only property
duration : integer (i).    % a write only property
duration : integer (o) (i).    % a normal property, which can be both written to and read from. This is equivalent to not writing anything
duration : integer.    % equivalent to the declaration above.</vip>
 
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.
As mentioned above properties are always implemented by get/set predicates even when the program implement them by a fact variable.


=== Properties from Interface ===
=== Properties from Interface ===
Line 111: Line 138:


<vipbnf><PropertiesFromInterface> :
<vipbnf><PropertiesFromInterface> :
     properties from <InterfaceName> <PpropertyName>-comma-sep-list-opt</vipbnf>
     properties from <InterfaceName> <PropertyName>-comma-sep-list-opt</vipbnf>


<vpbnf><PropertiesFromInterface></vpbnf> can only be used in interface definitions.
<vpbnf><PropertiesFromInterface></vpbnf> can only be used in interface definitions.

Latest revision as of 10:16, 10 July 2017

Properties are named values associated with classes and objects. Actually they are syntactic sugar for get/set predicates for the property value. And in that sense they are a language incarnation of a frequently used programming pattern.

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:

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

Property Declaration

PropertyDeclaration :
    PropertyName : PropertyType FlowPattern-list-opt
FlowPattern: one of
    (i)
    (o)

It is possible to get the value of a property that has the (o) flow, and it is possible to set the value of a property that has the (i) flow. If the flow patterns are not stated, both (i) and (o) are assumed, so it is possible bot to set and get the value of such properties.

Though it is legal to state (i) and (o) simultaneously, it is considered better practice to omit them in the get+set case.

Example Assume we declare them with an i/o pattern as:
properties
    durationO : real (o). % a get only property
    durationI : real (i). % a set only property
    durationIO : real (i) (o). % a "full" property, which can both be set and get.
    duration : real. % equivalent to the declaration above and preferred.

In the sequel we will use the use the following example:

Example
interface ip
properties
   duration : real.
   initialized : boolean (o).
   scale : real.
end interface
duration and scale are get+set properties, and initialized is a get-only property.

Properties are used like fact variables. It is possible to qualify properties for with a scope name or an object.

Example X is an object that supports the interface ip
X:duration := 5,
if true = X:initialized then ... else ... end if,
X:scale := 2.56,
....

Inside an implementation of a class that supports ip you access the properties as if they were facts.

duration := 5,
if true = initialized then ... else ... end if,
scale := 2.56,
....

Implementation

A property is implemented by defining a function for getting the value and a predicate to set it.

Example
clauses
    % implementation of the get function of the duration property
    duration() = duration_fact.
 
clauses
    % implementation of the set predicate of the duration property
    duration(D) :-
        duration_fact := D / scale.

Alternatively the property can be implemented as a fact variable with the same name as the property.

Example
facts
    % the initialized property is implemented by a fact variable
    initialized : boolean := false.
    % the scale property is implemented by a fact variable
    scale : real := 1.2

In this case the compiler will implicitly provide clauses that implement the get and set predicates.

Example For the two fact variable implementations above the compiler will provide clauses corresponding to this
clauses
    % implicit get clause for the initialized property
    initialized() = initialized.
 
clauses
    % implicit get clause for the scale property
    scale() = scale.
 
clauses
    % implicit set clause for the scale property
    scale(V) :-
        scale := V.
As mentioned below it would not be legal to state these clauses in a program.

It is illegal to have set and get predicates and a fact with the same name, meaning that a property is either implemented by programmer provided clauses or by a fact; mixed implementation is not possible.

Example We want to send a changed event when the duration property changes value. Therefore we have to implement the property by predicates, and use a fact variable with an other name for storing the value.
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).

It is not possible to use the duration predicates as predicates (they are not declared as predicates, but as a property; it is just the way the get and set of the property are implemented).

But in the predicate names are "used" - so you cannot declare predicates duration\1 or duration\0->.

As mentioned above properties are always implemented by get/set predicates even when the program implement them by a fact variable.

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:

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

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