The Types Package

OCL is a typed language. Each expression has a type which is either explicitly declared or can be statically derived.  Evaluation of the expression yields a value of this type. Therefore, before we can define expressions, we have to provide  a model for the concept of type. A metamodel for OCL types is shown in this section. Note that instances of the classes  in the metamodel are the types themselves (e.g. Integer) not instances of the domain they represent (e.g. -15, 0, 2, 3).

The model in Figure 5 shows the OCL types. The basic type is the UML Classifier, which includes all subtypes of  Classifier from the UML infrastructure.

In the model the CollectionType and its subclasses and the TupleType are special. One can never instantiate all collection  types, because there is an infinite number, especially when nested collections are taken in account. Users will never  instantiate these types explicitly. Conceptually all these types do exist, but such a type should be (lazily) instantiated by a  tool, whenever it is needed in an expression.

In comparison with UML 1.4 the type OclType has been removed from the type hierarchy. This means that a Classifier is  not a valid OCL expression any more.


BagType

BagType is a collection type which describes a multiset of elements where each element may occur multiple times in the  bag. The elements are unordered. Part of a BagType is the declaration of the type of its elements.

CollectionType

CollectionType describes a list of elements of a particular given type. CollectionType is an abstract class. Its concrete  subclasses are SetType, SequenceType and BagType types. Part of every collection type is the declaration of the type of  its elements, i.e. a collection type is parameterized with an element type. In the metamodel, this is shown as an  association from CollectionType to Classifier. Note that there is no restriction on the element type of a collection type.
This means in particular that a collection type may be parameterized with other collection types allowing collections to be  nested arbitrarily deep.

Associations
OclMessageType

OclMessageType describe ocl messages. Like to the collection types, OclMessageType describes a set of types in the standard library. Part of every OclMessageType is a reference to the declaration of the type of its operation or signal, i.e. an ocl message type is parameterized with an operation or signal. In the metamodel, this is shown as an association from OclMessageType to Operation and to Signal. OclMessageType is part of the abstract syntax of OCL, residing on M2 level. Its instances, called OclMessage, and subtypes of OclMessage, reside on M1 level.

Associations
OclModelElementType

OclModelElementType represents the types of elements that are ModelElements in the UML metamodel. It is used to  be able to refer to states and classifiers in e.g. oclInState(...) and oclIsKindOf(...)

OrderedSetType

OrderedSetType is a collection type which describes a set of elements where each distinct element occurs only once in  the set. The elements are ordered by their position in the sequence. Part of an OrderedSetType is the declaration of the  type of its elements.

SequenceType

SequenceType is a collection type which describes a list of elements where each element may occur multiple times in the  sequence. The elements are ordered by their position in the sequence. Part of a SequenceType is the declaration of the  type of its elements.

SetType

SetType is a collection type which describes a set of elements where each distinct element occurs only once in the set.
The elements are not ordered. Part of a SetType is the declaration of the type of its elements.

TupleType

TupleType (informaly known as record type or struct) combines different types into a single aggregate type. The parts of  a TupleType are described by its attributes, each having a name and a type. There is no restriction on the kind of types  that can be used as part of a tuple. In particular, a TupleType may contain other tuple types and collection types. Each  attribute of a TupleType represents a single feature of a TupleType. Each part is to uniquely identified by its name.

VoidType

VoidType represents a type that conforms to all types. The only instance of VoidType is OclVoid, which is further defined  in the standard library. Furthermore OclVoid has exactly one instance called OclUndefined.

Type Conformance

The type conformance rules are formally underpinned in the Semantics section of the specification. To ensure that the rules are accessible to UML modellers they are specified in this section using OCL. For this, the additional operation conformsTo(c : Classifier) : Boolean is defined on Classifier. It evaluates to true, if the self Classifier conforms to the argument c. The following OCL statements define type conformance for individual types.

BagType
  1. Different bag types conform to each other if their element types conform to each other.context BagType

  2. inv: BagType.allInstances()->forAll(b |
        self.elementType.conformsTo(b.elementType) implies self.conformsTo(b))

Classifier

  1. Conformance is a transitive relationship.
  2. context Classifier
    inv Transitivity: Classifier.allInstances()->forAll(x|Classifier.allInstances()
        ->forAll(y|
            self.conformsTo(x) and x.conformsTo(y)) implies self.conformsTo(y)))

  3. All classifiers except collections conform to OclAny.

    context Classifier
    inv: (not self.oclIsKindOf (CollectionType)) implies
        Primitive.allInstances()->forAll(p | (p.name = 'OclAny') implies self.conformsTo(p))

  4. Classes conform to superclasses and interfaces that they realize.

    context Class
    inv : self.generalization.parent->forAll (p |
        (p.oclIsKindOf(Class) or p.oclIsKindOf(Interface)) implies
            self.conformsTo(p.oclAsType(Classifier)))

  5. Interfaces conforms to super interfaces.

    context Interface
    inv : self.generalization.parent->forAll (p |
        p.oclIsKindOf(Interface) implies self.conformsTo(p.oclAsType(Interface)))

  6. The Conforms operation between Types is reflexive, a Classifier always conform to itself.

    context Classifier
    inv: self.conformsTo(self)

  7. The Conforms operation between Types is anti-symmetric.

    context Classifier
    inv: Classifier.allInstances()->forAll(t1, t2 |
        (t1.conformsTo(t2) and t2.conformsTo(t1)) implies t1 = t2)

CollectionType

  1. Specific collection types conform to collection type.

  2. context CollectionType
    inv: -- all instances of SetType, SequenceType, BagType conform to a
        -- CollectionType if the elementTypes conform
            CollectionType.allInstances()->forAll (c |
                c.oclIsTypeOf(CollectionType) and
                self.elementType.conformsTo(c.elementType) implies
                    self.conformsTo(c))

  3. Collections do not conform to any primitive type.

    context CollectionType
    inv: Primitive.allInstances()->forAll (p | not self.conformsTo(p))

  4. Collections of non-conforming types do not conform.

    context CollectionType
    inv: CollectionType.allInstances()->forAll (c |
        (not self.elementType.conformsTo (c.elementType)) implies (not self.conformsTo (c)))

OrderedSetType

  1. Different ordered set types conform to each other if their element types conform to each other.

  2. context OrderedSetType
    inv: OrderedSetType.allInstances()->forAll(s |
        self.elementType.conformsTo(s.elementType) implies self.conformsTo(s))


Primitive

  1. Integer conforms to real.

  2. context Primitive
    inv: (self.name = 'Integer') implies
        Primitive.allInstances()->forAll (p | (p.name = 'Real') implies
            (self.conformsTo(p))))

SequenceType
  1. Different sequence types conform to each other if their element types conform to each other.

  2. context SequenceType
    inv: SequenceType.allInstances()->forAll(s |
        self.elementType.conformsTo(s.elementType) implies self.conformsTo(s))

SetType

  1.  Different set types conform to each other if their element types conform to each other.

  2. context SetType
    inv: SetType.allInstances()->forAll(s |
        self.elementType.conformsTo(s.elementType) implies self.conformsTo(s))

TupleType

  1. Tuple types conform to each other when their names and types conform to each other. Note that allAttributes is an additional operation in the UML 1.4.

  2. context TupleType
    inv: TupleType.allInstances()->forAll (t |
        ( t.allAttributes()->forAll (tp |
            -- make sure at least one tuplepart has the same name
            -- (uniqueness of tuplepart names will ensure that not two
            -- tupleparts have the same name within one tuple)
            self.allAttributes()->exists(stp|stp.name = tp.name) and
            -- make sure that all tupleparts with the same name conforms.
            self.allAttributes()->forAll(stp | (stp.name = tp.name) and
            stp.type.conformsTo(tp.type))
        )
        implies
            self.conformsTo(t)
    ) )

VoidType
  1. Void conforms to all other types.

  2. context VoidType
    inv: Classifier.allInstances()->forAll (c | self.conformsTo (c))

Well-formedness Rules for the Types Package

BagType

  1. The name of a bag type is "Bag" followed by the element type's name in parentheses.

  2. context BagType
    inv: self.name = 'Bag(' + self.elementType.name + ')'

CollectionType

  1.  The name of a collection type is "Collection" followed by the element type's name in parentheses.

  2. context CollectionType
    inv: self.name = 'Collection(' + self.elementType.name + ')'

Classifier

  1. For each classifier at most one of each of the different collection types exist.\

  2. context Classifier
    inv: collectionTypes->select(oclIsTypeOf(CollectionType))->size() <= 1
    inv: collectionTypes->select(oclIsTypeOf(BagType ))->size() <= 1
    inv: collectionTypes->select(oclIsTypeOf(SequenceType ))->size() <= 1
    inv: collectionTypes->select(oclIsTypeOf(SetType ))->size() <= 1

OclMessageType

  1. OclMessageType has either a link with a Signal or with an operation, but not both.

  2. context OclMessageType
    inv: referredOperation->size() + referredSignal->size() = 1

  3. The parameters of the referredOperation become attributes of the instance of OclMessageType.

    context OclMessageType
    inv: referredOperation->size() = 1 implies
        self.feature = referredOperation.parameter.asAttribute()

  4. The attributes of the referredSignal become attributes of the instance of OclMessageType.

    context OclMessageType
    inv: referredSignal->size() = 1 implies
        self.feature = referredSignal.feature

OrderedSetType

  1. The name of a set type is "OrderedSet" followed by the element type's name in parentheses.

  2. context OrderedSetType
    inv: self.name = 'OrderedSet(' + self.elementType.name + ')'

SequenceType

  1. The name of a sequence type is "Sequence" followed by the element type's name in parentheses.

  2. context SequenceType
    inv: self.name = 'Sequence(' + self.elementType.name + ')'

SetType

  1. The name of a set type is "Set" followed by the element type's name in parentheses.

  2. context SetType
    inv: self.name = 'Set(' + self.elementType.name + ')'

TupleType

  1. The name of a tuple type includes the names of the individual parts and the types of those parts.

  2. context TupleType
    inv: name =
        'Tuple('.concat (
            Sequence{1..allAttributes()->size()}->iterate (pn; s: String = '' |
                let p: Attribute = allAttributes()->at (pn) in (
                    s.concat (
                        (if (pn>1) then ',' else '' endif)
                        .concat (p.name).concat (':')
                        .concat (p.type.name)
                    )
                 )
            )
        ).concat (')')


  3. All parts belonging to a tuple type have unique names.

    context TupleType
    inv: -- always true, because attributes must have unique names.

  4. A TupleType instance has only features that are Attributes (tuple parts).

    context TupleType
    inv: feature->forAll (f | f.oclIsTypeOf(Attribute))