.Open The Object Constraint Language . Introduction The Object Constraint Language - the $OCL is used to specify constraints on objects in the $UML. It has the power (but not syntax) of the Lower order Predicate Calculus ($LPC) plus simple $set_theory. Parts of the syntax seem to have been influenced by $Smalltalk. . Disclaimer -- Opinions expressed here may be Out of Date This page documents my understanding of the syntax and some of the semantics of the $OCL. This description is based on the 1997 version 1.1 and certain 1999 version 1.3 updates. The latest version is 2.0 (2006/05/01, 232 pages of PDF) and is under revision by the OMG (see below). . See Also The Object Management Group (OMG) .See http://www.omg.org/technology/documents/modeling_spec_catalog.htm#OCL maintains the standard. The Wikipedia .See http://en.wikipedia.org/wiki/Object_Constraint_Language has a very short introduction to the $OCL. The WikiWikiWeb .See http://c2.com/cgi/wiki?ObjectConstraintLanguage has a short discussion and some links. IBM holds a useful page .See http://www-4.ibm.com/software/ad/standards/ocl.html about the $OCL which includes links to a parser(Java in a .zip file) and a specification of the language in Adobe PDF format. More information can be found at .See http://www.klasse.nl/ocl/index.htm the Klasse Objecten Home. . Glossary UML::="Unified Modeling Language", .See http://www/dick/samples/uml.html XBNF::="BNF stretched to its limit", .See http://www/dick/samples/math.syntax.html LPC::="Lower Predicate Calculus", a standard logic, .See http://www/dick/maths/logic_10_PC_LPC.html OCL::="Object Constraint Language", .See http://www.rational.com/uml/resources/documentation/ocl .See http://www.software.ibm.com/ad/standards/ocl.html set_theory::=http://www.csci.csusb.edu/dick/maths/logic_30_Sets.html Smalltalk::=`Object oriented language developed at Xerox PARC by Alan Kay and friends`, .See http://www/dick/samples/smalltalk.html Smalltalk_methods::=http://www.csci.csusb.edu/dick/samples/smalltalk.methods.html. string_theory::=http://www.csci.csusb.edu/dick/maths/math_61_String_Theories.html, strings::=http://www.csci.csusb.edu/dick/maths/math_62_Strings.html. .Open Syntax . Notation The following $Syntax description uses the conventions of the $XBNF extended BNF including: O(_)::=`an optional (_)`. #(_)::=`any number of (_) including none`. N(_)::=`one or more of (_)`. For op, term, L(op, term)::=term #(op term), -- Infix operator expression. List(_)::= $L( "," , (_) ). . Grammar expression ::= $logical_expression. logical_expression ::= $L( $logical_operator, $relational_expression ). .As_is score > 88.33 and score <= 93.33 .As_is gender = #female or gender = #male .As_is p implies q .As_is left xor right .As_is next->isEmpty or value <= next.value .As_is self.grading and self.questions->size<10 .As_is p1 <> p2 implies p1.name <> p2.name .As_is Student.allInstances->forAll( p1, p2 | p1 <> p2 implies p1.name <> p2.name ) relational_expression ::= $additive_expression $O( $relational_operator $additive_expression ). .As_is score > 88.33 .As_is value <= next.value .As_is self.questions->size<10 additive_expression ::= $L( $add_operator, $multiplicative_expression ). .As_is golgafrensham + 42 .As_is golgafrensham - 42 .As_is self.questions->size+1 multiplicative_expression ::= $L( $multiply_operator, $unary_expression ). .As_is 2 * head .As_is 22 / 7 .As_is 20*self.questions->size unary_expression ::= #( $unary_operator ) $postfix_expression. .As_is - prefect .As_is not ford .As_is not self.questions->isEmpty postfix_expression ::= $primary_expression #($navigation_operator $feature_call ). .As_is self.questions .As_is employees->includes(#dent) .As_is self.questions->size .As_is self.employer->size .As_is self.employer->includes(self) .As_is self.employee->select (v | v.wages>10000 )->size .As_is Student.allInstances->forAll( p1, p2 | p1 <> p2 implies p1.name <> p2.name ) primary_expression ::= $literal_collection | $literal | $feature_call | "(" $expression ")" | $if_expression. .As_is 42 .As_is self .As_is #dent .As_is employer@pre .As_is MyClass::myMethod(myArgument) .As_is self.employee->exists (v | v = self ) .As_is Student.allInstances if_expression ::= "if" $expression "then" $expression "else" $expression "endif". .As_is if name = 'beeblebrox' then body->count(head) = 2 endif feature_call_parameters ::= "(" $O( $declarator ) ( $actual_parameter_list) ")". .As_is ( 42, #dent, x, self, 'beeblebrox') .As_is ( v:people | v.height < 6 ) .As_is ( p1, p2 | p1 <> p2 implies p1.name <> p2.name ) literal ::= $string | $number | "#" $name. .As_is 'beeblebrox' .As_is 42 .As_is #dent enumeration_type ::= "enum" "{" $List("#" $name ) "}". .As_is enum{ #female, #male } simple_type_Specifier ::= $path_type_name | $enumeration_type. literal_collection ::= $collection_kind "{" $O($expression_list_or_range) "}". (Set): .As_is Set { 1 , 2 , 5 , 88 } .As_is Set { 'apple' , 'orange', 'strawberry' } (Sequence): .As_is Sequence { 1, 3, 45, 2, 3 } .As_is Sequence { 'ape', 'nut' } .As_is Sequence{ 10..24 } (Bag): .As_is Bag {1 , 3 , 4, 3, 5 } expression_list_or_range ::= $expression $O( $N( "," $expression ) | ( ".." $expression )). .As_is 12,13,15 .As_is 12..15 feature_call ::= $path_name $O($time_expression) $O($qualifiers) $O($feature_call_parameters). qualifiers ::= "[" $actual_parameter_list "]". declarator ::= $List($name) $O( ":" $simple_type_Specifier ) "|". path_type_name ::= $type_name #( $double_colon $type_name). path_name ::= ( $type_name | $name ) #( $double_colon ( $type_name | $name ) ). .As_is MyClass::myAttribute time_expression ::= "@" $name. .As_is @pre actual_parameter_list ::= $List( $expression ). .As_is 1+1, 2, 3 . Lexicon double_colon::= $colon $colon. colon::= ":". logical_operator ::= "and" | "or" | "xor" | "implies". collection_kind ::= "Set" | "Bag" | "Sequence" | "Collection". relational_operator ::= "=" | ">" | "<" | ">=" | "<=" | "<>". add_operator ::= "+" | "-". multiply_operator ::= "*" | "/". unary_operator ::= "-" | "not". navigation_operator::= "." | "->" number ::= $digit #$digit. type_name ::= $upper #idchar. name ::= $lower #$idchar. idchar::= $letter | $digit | "_". string::="'" #( $normal_char | $backslash $escape_sequence ) "'". backslash::="\\". normal_char::=char ~ ("'" | $backslash | $newline ). newline::= `Newline and carriage return characters shown as "\n""\r" in C and C++` . escape_sequence ::= "n" | "t" | "b" | "r" | "f" | $backslash | "'" | $doublequote | $ASCII_code_number. -- compare with C/C++/Java ASCII_code_number::=$odigit $O( $odigit ) | ("0".."3") $odigit $odigit doublequote::="\"". digit::="0".."9". odigit::=octal_digit. octal_digit::="0".."7". letter::= $upper | $lower. upper::="a".."z". lower::="A".."Z". .Close Syntax .Open Notes .Open Using the OCL . Comments Comments in OCL are written after two dashes. Everything after the two dashes up to and including the end of line is comment. For example: .As_is -- this is a comment . Class Invariants The context is shown first and then the invariant: .As_is context Student .As_is inv: self.age >= 0 . Operation Contracts In text the context of the operation is listed and then the pre-, and post-, conditions. .As_is context Typename::operationName(parameter1 : Type1, ... ): ReturnType .As_is pre : parameter1 > ... .As_is post: result = ... (In an early version the context was underlined and the word "context" not used). In a post condition use "@pre" to indicate the value before the operation and "result" is the value returned. . Operation Bodies These can be specified like this .As_is context Typename::operationName(parameter1 : Type1, ... ): ReturnType .As_is pre: some precondition .As_is body: expression representing the body of the operation . Initial Values These can be specified like this for an attribute or association end: .As_is context Typename::propertyName: Type .As_is init: expression representing the initial value . Derived Attributes These can be specified like this for an attribute or association end: .As_is context Typename::propertyName: Type .As_is derive: expression representing the initial value .Close Using the OCL . Special Symbols self::Object. self refers to an object of the class being constrained .As_is self.numberOfEmployees In most cases, `self` can be left out, because the context is clear, as in the above examples. result::Object. `result` is used in a post-condition inside an operation specification, to indicate the object returned . Local Variables Within a context the lexeme "Let" allows the definition of a shorthand "variable" name for an expression: .As_is let variable : type = expression. . OCL Types Each class in a model that uses the UML defines a new type. There are other predefined types: type::= $pathname | $predefined_type. predefined_type::= $basic_type | "OclExpression" | "OclType" | "OclAny". basic_type::= "Integer" | "Real" | "String" | "Boolean". OCL Types have the following features: .Box For T:OclType. T.allInstances :: Set(T), set of all instances of a type T in model. T.name :: String, the name of the type. T.attributes :: Set(String), the set of names of attributes of T as defined in the model. T.associationEnds: Set(string), set of names of navigable roles in model. T.operations :: Set(string), type.supertypes:: Ste(OclType). .Close.Box . Properties of objects of Any Type OclAny::=following .Net For o, o1:object, T: Types, s:`possible states of object o in model`. o = o1::Boolean. o <> o1::Boolean. o.oclIsKindOf(T):: Boolean. o.oclIsTypeOf(T):: Boolean. o.oclAsType(T)::T, cast. o.oclInState(s)::Boolean, new with 1.3. .Close.Net . Navigation Starting from a specific object (or a $path_name), we can navigate an association on the class diagram to refer to other objects and their properties. To do so, we navigate the association by using the opposite association-end: .As_is object.rolename .See primary_expression The value of this expression is the set of objects on the other side of the role name association. If the multiplicity of the association-end has a maximum of one ("0..1" or "1"), then the value of this expression is an object. If the multiplicity is "0..1" then the result is an empty set if there is no object, otherwise it is the unique objet. Navigation expression generate $Collections of objects. By default, navigation will result in a Set. When the association on the Class Diagram is adorned with {ordered}, the navigation results in a Sequence. Collections, like Sets, Bags and Sequences, are predefined types in OCL. They have a large number of predefined operations on them. .As_is collection->operation(arguments) . Collections Collection(T)::=Set(T) | Sequence(T) | Bag(T). Collections can be Sets, Sequences, and Bags. An object can occur at most once in a Set but many times in a Bag. It occurs at a particular position in Sequence. See $literal_collection in the grammar above. Given a typename T then T.allInstances is the Set of all objects of type T. . Operations on Collections Collections have many useful `properties`. These are added to the $OCL to give it the power of symbolic logic ($LPC) and naive set theory. Properties of collections are accessed by using an arrow '->' followed by the name of the property. There are many of these. They seem to have been borrowed from $Smalltalk [$Smalltalk_methods]. Many of the properties of collections result in collections. This means that they can be chained together: .As_is self.employee->select (v | v.wages>10000 )->size See $postfix_expression in the grammar above. The following is a list of some of the commonest ones. .Box For c,c1:$Collection(T), v:variable, T,T1,T2:Type, e:expression, b:BooleanExpression, o1:object. (casts): c->asSequence::Sequence(T), c->sortBy(...)::Sequence(T). (size): c->size :: Integer. (isEmpty): c->isEmpty :: Boolean. |-(axiom1): c->isEmpty = (c->size = 0). (count): c->count(o1) :: Integer=`count of occurrences of o1 in c`. |-(axiom2): c->count(o1) = c->select(v | v=o1)->size. (sum): c->sum :: T. (filters): $select, $reject, $collect, etc .Box (select): c->select( v : T | b(v) ):: Collection(T), generates a collection by taking only elements `v` in `c` for which `e`(`v`) is true. c->select( b ) :: Collection(T). v->select( v | e(v) ):: Collection(T). (reject): c->reject( v : T | b(v) ):: Collection(T) = c->select(v:T | not(e(v))). (collect): c->collect( v : T | e(v) ):: Collection(T), generates a collection made up of `e`(`v`) as `v` goes thru collection `c`. c->collect( v | e(v) ):: Collection(T). c->collect( e ):: Collection(T). .Close.Box (quantifiers): $forAll and $exists. Compare with $LPC .Box (forAll): c->forAll( v : T | b ):: Boolean = for all v:c&T ( b ). c->forAll( v | b ):: Boolean. c->forAll( b ):: Boolean. (exists): c->exists( v : T | b ):: Boolean = for some v:c&T ( b ). c->exists( v | b ):: Boolean. c->exists( b ):: Boolean. .Close.Box (iterate): c->iterate( v : T1; a : T2 = e0 | e(v,a) )::collection(T). The variable `v` is the iterator, as in the definition of select, forAll, etc. `v` takes each value in the collection `c` in turn. The variable `a` is the accumulator. The `a` gets an initial value `e0`. The `e(v,a)` is an expression that is repeatedly assigned to `a`. For example |- c->sum = c->iterate(v, a=0 | a+v). |- c->size = c->iterate(v, a=0 | a+1). (sets): $includes, $excludes, $union, $intersection, $including, and $excluding. Compare with $set_theory. Plus (new in 1.3) unique, excludes, excludesAll .Box (includes): c->includes(o) :: Boolean= true if and only if o in c. (union): c->union(c2) :: Set(T) = c|c2. (intersection): c->intersection(c2) :: Set(T)= c&c2. (including): c->including(o) ::Set(T) = c | {o}. (excluding): c->excluding(o) :: Set(T) = c ~ {o}. .Close.Box (sequences): $append, $prepend, $at, etc etc. See my $strings and $string_theory. .Box (append): s->append (o) :: Sequence(T) = s ! o, put o after s. (prepend): s->prepend(o) :: Sequence(T) = o ! s, put o at the front of s. (at): s->at(i ) :: T = s[i], pick out the i'th item in s. .Close.Box .Close.Box . Undefined expressions Whenever an OCL expression is being evaluated, there is a possibility that one or more of the queries in the expression are undefined. If this is the case, then the complete expression will be undefined. Two exceptions are the boolean operators `and` + `or`: .Box True OR-ed with anything is True False AND-ed with anything is False .Close.Box Notice, that `if-then-else-endif` does not evaulate all its arguments and so can be used to avoid an undefined object. In later OCL versions .As_is oclUndefined() will recognize an undefined object and return `True` otherwise it returns `False`. . Shorthand notation for collect .Box In general, when we apply a property to a Collection of Objects, then the OCL will automatically be interpret it as a $collect over the members of the Collection with the specified property. So .As_is self.employee->collect(birthdate) is normally written .As_is self.employee.birthdate and it means `all the employee's birthdates`. .Close.Box .Close Notes .Close The Object Constraint Language