If the constraint is shown in a diagram, with the proper stereotype
and the dashed lines to connect it to its contextual element, there is
no need for an explicit context declaration in the test of the
constraint.
The context declaration is optional.
For example, if in the context of the Company type in Figure 1 , the following expression would specify an invariant that the number of employees must always exceed 50:
self.numberOfEmployees > 50
where self is an instance of type Company. (We can view self as the object from where we start evaluating the expression.) This invariant holds for every instance of the Company type.
The type of the contextual instance of an OCL expression, which is part of an invariant, is written with the context keyword, followed by the name of the type as follows. The label inv: declares the constraint to be an «invariant» constraint.
context
Company
inv:
self.numberOfEmployees
> 50
In most cases, the keyword self can be dropped because the context is clear, as in the above examples. As an alternative for self, a different name can be defined playing the part of self:
context c :
Company
inv:
c.numberOfEmployees
> 50
This invariant is equivalent to the previous one.
Optionally, the name of the constraint may be written after the inv keyword, allowing the constraint to be referenced by name. In the following example the name of the constraint is enoughEmployees. In the UML 1.4 metamodel, this name is a (meta-)attribute of the metaclass Constraint that is inherited from ModelElement.
context c :
Company
inv enoughEmployees:
c.numberOfEmployees
> 50
context
Typename::operationName(param1
: Type1, ... ): ReturnType
pre : param1
> ...
post: result
= ...
The name self can be used in the expression referring to the object on which the operation was called. The reserved word result denotes the result of the operation, if there is one. The names of the parameters (param1) can also be used in the OCL xpression. In the example diagram, we can write:
context
Person::income(d
: Date) : Integer
post: result
= 5000
Optionally, the name of the precondition or postcondition may be written after the pre or post keyword, allowing the constraint to be referenced by name. In the following example the name of the precondition is parameterOk and the name of the postcondition is resultOk. In the UML metamodel, these names are the values of the attribute name of the metaclass Constraint that is inherited from ModelElement.
context
Typename::operationName(param1
: Type1, ... ): ReturnType
pre parameterOk:
param1 > ...
post resultOk
: result = ...
The above context declaration is precise enough when the package in which the Classifier belongs is clear from the environment. To specify explicitly in which package invariant, pre or postcondition Constraints belong, these constraints can be enclosed between 'package' and 'endpackage' statements. The package statements have the syntax:
package
Package::SubPackage
context X inv:
... some invariant ...
context
X::operationName(..)
pre: ... some
precondition ...
endpackage
An OCL file (or stream) may contain any number package statements,
thus
allowing all invariant, preconditions and postconditions to be written
and stored in one file. This file may co-exist with a UML model as a
separate
entity.
context
Typename::operationName(param1
: Type1, ... ): ReturnType
body: -- some
expression
The expression must conform to the result type of the operation. Like in the pre- and postconditions, the parameters may be used in the expression. Pre-, and postconditions, and body expressions may be mixed together after one operation context. For example:
context
Person::getCurrentSpouse()
: Person
pre:
self.isMarried
= true
body:
self.mariages->select(
m | m.ended = false ).spouse
context
Typename::attributeName:
Type
init: -- some
expression representing the initial value
context
Typename::assocRoleName:
Type
derive: -- some
expression representing the derivation rule
The expression must conform to the result type of the attribute. In the case the context is an association end the expression must conform to the classifier at that end when the multiplicity is at most one, or Set or OrderedSet when the multiplicity may be more than one. Initial, and derivation expressions may be mixed together after one context. For example:
context
Person::income
: Integer
init:
parents.income->sum()
* 1% -- pocket allowance
derive: if
underAge
then
parents.income->sum()
* 1% -- pocket allowance
else job.salary --
income
from regular job
endif