Issue 16357: UML: unification of OCL declarations (uml2-rtf) Source: Model Driven Solutions (Dr. Edward Willink, ed(at)willink.me.uk) Nature: Uncategorized Issue Severity: Summary: UML supports declarations of elements with multiplicity bounds; OCL does not OCL supports declarations of nested collections; UML does not A possible unification of the capabilities/syntaxes could be achieved by UML introducing Bag/OrderedSet/Sequence/Set as alternatives for {ordered,unique} etc and OCL adopting <> brackets and multiplicity qualification. Concrete Syntax ----------------------- The syntax is not obvious All of Set<Type[0..5]> or Set<Type>[0..5] or Set<Type : 0..5> or Set[0..5]<Type> could be a bounded Set. All of Set<Set<Type[0..5]>[0..5]> or Set<Set<Type>[0..5]>[0..5] or Set<Set<Type : 0..5>: 0..5> or Set[0..5]<Set[0..5]<Type>> could be a 2D bounded Set. Set[0..5]<Set[0..5]<Type>> seems to best localize the multiplicity for the collection-type. Abstract Syntax ---------------------- UML embeds its 'collection' declaration in a MultiplicityElement, which doesn't scale to nested collections. MultiplicityElement is a nuisance for OCL since it provides an alternate form of collection declaration to the CollectionType type constructor. A unified behaviour could deprecate MultiplicityElement and introduce a CollectionType type constructor with ordered, unique, lower, upper in addition to signature attributes. Nullable Unit Collection Semantics ----------------------------------------------- So far so good, but there is an OCL semantic issue that is exposed by a compatibility conversion of MultiplicityElement. Currently MyType[0..1] is a nullable non-collection, so an OCL navigation of an unspecified value gives a null, which crashes any navigated collect iteration such as a->collect(b)->collect(c). A crash on a null object is confusing with respect to an empty collection for which iterations just skip the empty. Deprecating MultiplicityElement would convert MyType[0..1] to Set[0..1]<MyType>; clearly a collection not an object, which avoids the value-dependence that a MultiplicityElement that happens to have a unit upper bound is not a Collection. There is now no way to express a nullable object, so perhaps a { nullable } constraint can be supported. This restores the semantic coverage and conversion compatibility: [1] is ignored, [0..1] is treated as {nullable} and other multiplicities become correspondingly bounded collections. This also has the benefit that ordered and unique would cease to have any relevant semantics for non-collection objects thereby eliminating OCL's dilemma as to whether a [1] { ordered, unique } should be converted to a unit OrderedSet rather than a unit Set by the -> operator. However, we can now wonder what the difference is between MyType{nullable} and Bag[0..1]<MyType> and why modelers should prefer one or the other. A difference is that in OCL a->collect(b)->collect(c) will crash if b is a null MyType{nullable} whereas it will skip over a null for the empty collection. This seems really bad; a collect over a structurally valid model crashes. But is this OCL just throwing a problem over the fence to UML? Perhaps the problem is that OCL 2.3 has still not resolved the distinct semantics of null and invalid. Perhaps, since OclVoid conforms to all types, null has null/empty values of all properties with a 0 lower bound. Therefore null.oclAsType(NamedElement).name could be null rather than invalid, and so a->collect(b)->collect(c) should crash on invalid structures, but return a result including interspersed nulls for intermediate collects at null nullable elements. So the difference between MyType{nullable} and Bag[0..1]<MyType> is that: MyType{nullable} is what modelers will normally use. It is an object that may be null and always participates in an iteration as exactly one value, which may be null which may in turn participate in strucyurally valid iterations. Bag[0..1]<MyType> is a clumsy but consistent alternative. It is a unit collection that may be empty and only participates in an iteration when not empty. Resolution: Revised Text: Actions taken: July 8, 2011: received issue Discussion: End of Annotations:===== ronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: Av0EADzgFk7Unw4R/2dsb2JhbABTp0N3iH2kFZ8ihjgEl0mLSA Date: Fri, 08 Jul 2011 11:48:48 +0100 From: Ed Willink User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; en-GB; rv:1.9.2.13) Gecko/20101207 Thunderbird/3.1.7 To: issues@omg.org Subject: UML: unification of OCL declarations Hi Juergen: This is a UML issue; please CC OCL-rtf. UML supports declarations of elements with multiplicity bounds; OCL does not OCL supports declarations of nested collections; UML does not A possible unification of the capabilities/syntaxes could be achieved by UML introducing Bag/OrderedSet/Sequence/Set as alternatives for {ordered,unique} etc and OCL adopting <> brackets and multiplicity qualification. Concrete Syntax ----------------------- The syntax is not obvious All of Set or Set[0..5] or Set or Set[0..5] could be a bounded Set. All of Set[0..5]> or Set[0..5]>[0..5] or Set: 0..5> or Set[0..5]> could be a 2D bounded Set. Set[0..5]> seems to best localize the multiplicity for the collection-type. Abstract Syntax ---------------------- UML embeds its 'collection' declaration in a MultiplicityElement, which doesn't scale to nested collections. MultiplicityElement is a nuisance for OCL since it provides an alternate form of collection declaration to the CollectionType type constructor. A unified behaviour could deprecate MultiplicityElement and introduce a CollectionType type constructor with ordered, unique, lower, upper in addition to signature attributes. Nullable Unit Collection Semantics ----------------------------------------------- So far so good, but there is an OCL semantic issue that is exposed by a compatibility conversion of MultiplicityElement. Currently MyType[0..1] is a nullable non-collection, so an OCL navigation of an unspecified value gives a null, which crashes any navigated collect iteration such as a->collect(b)->collect(c). A crash on a null object is confusing with respect to an empty collection for which iterations just skip the empty. Deprecating MultiplicityElement would convert MyType[0..1] to Set[0..1]; clearly a collection not an object, which avoids the value-dependence that a MultiplicityElement that happens to have a unit upper bound is not a Collection. There is now no way to express a nullable object, so perhaps a { nullable } constraint can be supported. This restores the semantic coverage and conversion compatibility: [1] is ignored, [0..1] is treated as {nullable} and other multiplicities become correspondingly bounded collections. This also has the benefit that ordered and unique would cease to have any relevant semantics for non-collection objects thereby eliminating OCL's dilemma as to whether a [1] { ordered, unique } should be converted to a unit OrderedSet rather than a unit Set by the -> operator. However, we can now wonder what the difference is between MyType{nullable} and Bag[0..1] and why modelers should prefer one or the other. A difference is that in OCL a->collect(b)->collect(c) will crash if b is a null MyType{nullable} whereas it will skip over a null for the empty collection. This seems really bad; a collect over a structurally valid model crashes. But is this OCL just throwing a problem over the fence to UML? Perhaps the problem is that OCL 2.3 has still not resolved the distinct semantics of null and invalid. Perhaps, since OclVoid conforms to all types, null has null/empty values of all properties with a 0 lower bound. Therefore null.oclAsType(NamedElement).name could be null rather than invalid, and so a->collect(b)->collect(c) should crash on invalid structures, but return a result including interspersed nulls for intermediate collects at null nullable elements. So the difference between MyType{nullable} and Bag[0..1] is that: MyType{nullable} is what modelers will normally use. It is an object that may be null and always participates in an iteration as exactly one value, which may be null which may in turn participate in strucyurally valid iterations. Bag[0..1] is a clumsy but consistent alternative. It is a unit collection that may be empty and only participates in an iteration when not empty. Regards Ed Willink