Escaping Types categories
Methods and Types
Selectors, Properties and Operations
Iterations

Selectors, Properties and Operations

As we said previously, CLAIRE supports two syntaxes for using selectors, f(...) and (.... f ....). The choice only exists when the associated methods have exactly two arguments. The ability to be used with an infix syntax is attached to the property f :
 f :: operation()
Once f has been declared as an operation, CLAIRE will check that it is used as such subsequently. Restrictions of f can then be defined with the usual syntax :
 f(x:integery:integer: ...
Note that declaring f as an operation can only be done when no restriction of f is known. If the first appearance of f is in the declaration of a method, f is considered as a normal selector and its status cannot be changed thereafter. Each operation is an object (inherits from property) with a precedence slot that is used by the reader to produce the proper syntax tree from expressions without parentheses.
 gcd :: operation(precedence = precedence(/))
 12 + 3 gcd 4 // same as 12 + (3 gcd 4)
So far we have assumed that any method definition is allowed, provided that inheritance conflict may cause warning. Once a property is compiled, CLAIRE uses a more restrictive approach since only new methods that have an empty intersection with existing methods (for a given property) are allowed. This allows the compiler to generate efficient code. It is possible to keep the "open" status of a property when it is compiled through the abstract declaration.
 abstract(f)
Such a statement will force CLAIRE to consider f as an "abstract" parameter of the program that can be changed at any time. In that case, any re-definition of f (any new method) will be allowed. When defining a property parameter, one should keep in mind that another user may redefine the behavior of the property freely in the future.

It is sometimes useful to model a system with redundant information. This can be done by considering pairs of relations inverse one of another. In this case the system maintains the soundness of the database by propagating updates on one of the relations onto the other. For example if husband is a relation from the class man onto the class woman and wife a relation from woman to man, if moreover husband and wife have been declared inverse one of another, each modification (addition or retrieval of information) on the relation husband will be propagated onto wife. For example husband(mary) := john will automatically generate the update wife(john) := mary. Syntactically, relations are declared inverses one of another with the declaration :
 inverse(husband:= wife
This can be done for any relation: slots and tables. Inverses introduce an important distinction between multi-valued relations and mono-valued relations. A relation is multi-valued in CLAIRE when its range is a subset of bag (i.e. a set or a list). In that case the slot multivalued? of the relation is set to true and the set associated with an object x is supposed to be the set of values associated with x through the relation.

This has the following impact on inversion. If r and s are two mono-valued relations inverse one of another, we have the following equivalence :
 s(x= y <=> r(y= x
In addition, the range of r needs to be included in the domain of s and conversely. The meaning of inversion is different if r is multi-valued since the inverse declaration now means :
 s(x= y <=> x E r(y)
Two multi-valued relations can indeed be declared inverses one of another. For example, if parents and children are two relations from person to set[person] and if inverse(children) = parents, then :
 children(x= {y in person | x % parents(y)}
Modifications to the inverse relation are triggered by updates (with :=) and creations of objects (with filled slots). Since the explicit inverse of a relation is activated only upon modifications to the database (it is not retroactive), one should always set the declaration of an inverse as soon as the relation itself is declared, before the relation is applied on objects. This will ensure the soundness of the database. To escape the triggering of updates to inverse relations, the solution is to fill the relation with the method put instead of :=. For example, the following declaration :
 let john := person() in (put(wife,john,mary), john)
does the same as :
 john :: person(wife = mary)
without triggering the update husband(mary) := john.


categories Selectors, Properties and Operationsnormal dispatch Kernel method

inverse(r:relation) -> relation

r.inverse contains the inverse relation of r. If the range of r inherits from bag then r is considered multi-valued by default. If r and its inverse are mono-valued then if r(x) = y then inverse(r)(y) = x. If they are multi-valued, then inverse(r)(y) returns the set (resp. list) of all x such that (y % r(x)).