In OCL, a number of basic types are predefined and available to
the modeler at all time. These predefined value types are independent
of
any object model and part of the definition of OCL.
The most basic value in OCL is a value of one of the basic types. The
basic types of OCL, with corresponding examples of their values, are
shown
in Table 2.
Table 2 - Basic Types
|
|
Boolean | true,false |
Integer | 1, -5, 2, 34, 26524, .. |
Real | 1.5, 3.14, ... |
String | 'To be or not to be...' |
OCL defines a number of operations on the predefined types. Table 3
gives some examples of the operations on the
predefined types. See Section "The
OCL Standard Library - Primitive Types" for a complete list
of
all operations.
Table 3 - Operations on predefined types
type | operations |
Integer | *, +, -, /, abs() |
Real | *,+, -, /, floor() |
Boolean | and, or, xor,not, implies, if-then-else |
String | concat(), size(), substring() |
Collection, Set, Bag, Sequence and Tuple are basic types as well.
Their
specifics will be described in the upcoming sections.
context Person inv:
gender
= Gender::male
context
Person
inv:
let income :
Integer = self.job.salary->sum()
in
if isUnemployed
then
income < 100
else
income >= 100
endif
A let expression may be included in any kind of OCL expression. It
is
only
known within this specific expression.
context
Person
def: income :
Integer = self.job.salary->sum()
def: nickname
: String = 'Little Red Rooster'
def: hasTitle(t
: String) : Boolean = self.job->exists(title = t)
The names of the attributes / operations in a let expression may not conflict with the names of respective attributes/ associationEnds and operations of the Classifier.
Using this definition syntax is identical to defining an
attribute/operation
in the UML with stereotype «OclHelper» with an attached OCL
constraint for its derivation.
An OCL expression in which all the types conform is a valid expression. An OCL expression in which the types don't conform is an invalid expression. It contains a type conformance error. A type type1 conforms to a type type2 when an instance of type1 can be substituted at each place where an instance of type2 is expected. The type conformance rules for types in the class diagrams are simple.
Table 4 - Type conformance rules
|
|
|
Set(T1) | Collection(T2) | if T1 conforms to T2 |
Sequence(T1) | Collection(T2) | if T1 conforms to T2 |
Bag(T1) | Collection(T2) | if T1 conforms to T2 |
Integer | Real |
The conformance relation between the collection types only holds if they are collections of element types that conform to each other. See Section 7.5.13, "Collection Type Hierarchy and Type Conformance Rules," for the complete conformance rules for collections.
Table 5 provides examples of valid and invalid expressions.
Table 5 - Valid Expressions
|
|
|
1 + 2 * 34 | yes | |
1 + 'motorcycle' | no | type String does not conform to type Integer |
23 * false | no | type Boolean does not conform to Integer |
12 + 13.5 | yes |
When it is certain that the actual type of the object is the
subtype,
the object can be re-typed using the operation
oclAsType(OclType). This operation results in the same object,
but the known type is the argument OclType. When there is an
object
object
of type Type1 and Type2 is another type, it is allowed
to
write:
object.oclAsType(Type2) --- evaluates to object with type Type2
An object can only be re-typed to one of its subtypes; therefore, in the example, Type2 must be a subtype of Type1.
If the actual type of the object is not a subtype of the type to
which
it is re-typed, the expression is undefined (see
("Undefined Values")).
Parentheses `(' and `)' can be used to change precedence.
a + b
is conceptually equal to the expression:
a.+(b)
that is, invoking the `+' operation on a with b as the parameter to the operation.
The infix operators defined for a type must have exactly one
parameter.
For the infix operators `<`, `>', `<=', `>=',
`<>',`and', `or',
and `xor' the return type must be Boolean.
Some expressions will, when evaluated, have an undefined value. For instance, typecasting with oclAsType() to a type that the object does not support or getting the ->first() element of an empty collection will result in undefined. In general, an expression where one of the parts is undefined will itself be undefined. There are some important exceptions to this rule, however. First, there are the logical operators:
The IF-expression is another exception. It will be valid as long as the chosen branch is valid, irrespective of the value of the other branch.
Finally, there is an explicit operation for testing if the value of
an expression is undefined. oclIsUndefined() is an operation on OclAny
that results in True if its argument is undefined and False otherwise.