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.
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.
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.
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:
interface ip properties duration : real. initialized : boolean (o). scale : real. end interface
Properties are used like fact variables. It is possible to qualify properties for with a scope name or an object.
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, ....
A property is implemented by defining a function for getting the value and a predicate to set it.
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.
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.
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.
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.
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.
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.
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.