• addrole(vx) – Add vx to the collection-valued as-
sociation end role
• removerole(vx) – Remove vx from the collection-
valued association end role
• setrole(i,vx) – Set the i-th element of a sequence-
valued association end role to vx.
Table 1 shows examples of wpc calculations for
these different kinds of operation, for local class in-
variants P of the class to which the operation belongs.
Table 1: Local constraint wpc calculations.
Operation act Weakest precondition [act]P
setatt(v) P[v/att]
addrole(vx) P[(role∪ {vx})/role]
removerole(vx) P[(role− {vx})/role]
setrole(i, vx) P[(role⊕ {i 7→ vx})/role]
In the example specification, br is a local feature
of A, so the calculations of Table 1 apply to give the
condition
x = v.cr.z.sum
which must be established in order that setbr(v) re-
establishes the constraint.
In other words, the code of setbr(v) must perform
both its basic action
br = v
and the additional action
x = v.cr.z.sum
derived from the constraint. These actions can be per-
formed in parallel or sequentially in either order, as
neither action writes to data read by the other.
We can derive similar change-propagation code
for addbr(vx) and removebr(vx).
More interesting, and more challenging, is the
case of actions which affect non-local (ie., global)
constraints. For this example, changes to cr and to
z are in this category. The response to such changes
is performed in a class called Controller, which has
access to all objects of the system. In this class are
operations setatt(obj : C, v : T) which apply setatt(v)
to object obj, addrole(obj : C,vx : D) which apply
addrole(vx) to obj, and removerole(obj : C,vx : D)
which apply removerole(vx) to obj.
Globally, a constraint P based on class A has the
meaning that for all instances of A, P holds:
A→forAll(P)
Table 2 shows the response code for such global
operations, where A→forAll(P) contains the modified
feature f of the operation, and this is not a local fea-
ture of the class A upon which the constraint is based.
Table 2: Global operation wpc calculations.
Operation act Weakest precondition [act]P
setatt(ob,v) A→forAll(ob ∼ self implies
P[((ref − {ob}).att∪ {v})/ref .att])
setrole(ob,v) A→forAll(ob ∼ self implies
P[((ref − {ob}).role∪ v)/ref .role])
addrole(ob,vx) A→forAll(ob ∼ self implies
P[(ref.role∪ {vx})/ref.role])
removerole(ob,vx) A→forAll(ob ∼ self implies
P[((ref − {ob}).role ∪
(ob.role− {vx}))/ref.role])
In the second, third and fourth cases, role is a many-
valued association end.
In each case the condition ob ∼ self expresses that
the object ob is reachable via associations of the sys-
tem from self, a specific object of A. ref is the nav-
igation route from self to role, ie, role occurs in an
expression ref.role in P. The computation is iterated
over all the occurrences of the feature in P.
In the example specification, this results in the fol-
lowing response code in addcr(bx, crxx):
A→forAll(bx : br implies
x = (br.cr∪ {crxx}).z.sum)
This defines a for loop over the instances of A. Only
the elements of A linked to bx via br need to modify
their x values to maintain the global constraint: other
instances of A cannot be affected by the change to
bx.cr.
In some cases a fixpoint computation is needed to
enforce a constraint. An example is the calculation of
the maximum inheritance depth in a class diagram. If
generalisations have an integer attribute depth to ex-
press their depth in the inheritance hierarchy, this fea-
ture is characterised by the two constraints:
Generalization→forAll(g |
g.general.generalization.size = 0 implies
g.depth = 1)
Generalization→forAll(g |
g.general.generalization.size > 0 implies
g.depth = 1 +
g.general.generalization.depth.max)
Since depth is both read and written in the second
constraint, a fixpoint iteration is used to enforce it.
From the computed response codes, complete
Java implementations of the operations of individual
classes and the controller class can be synthesised.
These operations are guaranteed to maintain the in-
variants (assuming the correctness of the Java virtual
machine, the operating system and hardware, etc).
In some cases a constraint Cn cannot be used to
produce executable response code, but instead it is
maintained by checking if application of an operation
SynthesisofSoftwarefromLogicalConstraints
357