Issue 14197: OCL 2.0, 2.1 inconsistent definition of null and invalid (ocl2-rtf) Source: Model Driven Solutions (Dr. Edward Willink, ed(at)willink.me.uk) Nature: Uncategorized Issue Severity: Summary: The attached surprisingly large set of revised text recommendations endeavours to resolve every inconsistent use of invalid and null/void types and the failure to update the specification when undefined was split into null and invalid. The recommendations also correct many conversion errors that crept in when Word Processor formats were changed. Once these changes are incorporated, a very careful proof read against at least Annex A of 03-01-07 should be performed. The initial discussion identifies that the approved resolutions of Issues: 6611, 10433, 10434, 12349, 12378, 12484 and 12485 are at best deficient Resolution: Revised Text: In 7.4.10 replace Undefined Values 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. by 7.4.11 Invalid Values Some expressions will, when evaluated, have an invalid 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 invalid. In general, an expression where one of the parts is null or invalid will itself be invalid. In 7.4.10 replace 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. by 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 null or invalid and False otherwise. In 7.7.2 last sentence replace If message.hasReturned() is false, then message.result() will be undefined. by If message.hasReturned() is false, then message.result() will be invalid. In 8.2 VoidType replace VoidType represents a type that conforms to all types. by VoidType is the metaclass of the OclVoid type that conforms to all types except the OclInvalid type. In 8.2 VoidType replace Note that in contrast with OclInvalid null is a valid value and as such can be owned by collections. by Note that in contrast with invalid, null is a valid value and as such can be owned by collections. In 8.2.1 InvalidType replace [1] Invalid conforms to all other types except OclVoid. context InvalidType inv: Classifier.allInstances()->forAll (c | not c.oclIsTypeOf(OclVoid) implies self.conformsTo (c)) by [1] OclInvalid conforms to all other types. context InvalidType inv: Classifier.allInstances()->forAll (c | self.conformsTo (c)) In 8.2.1 VoidType replace [1] Void conforms to all other types except OclInvalid. by [1] OclVoid conforms to all other types except OclInvalid. In 9.3 VariableDeclarationCS replace -- The value OclUndefined is used when no type has been given in the concrete syntax. -- Production rules that use this need to check on this type. VariableDeclarationCS.ast.type = if typeCS->notEmpty() then typeCS.ast else OclUndefined endif by -- The value null is used when no type has been given in the concrete syntax. -- Production rules that use this need to check on this type. VariableDeclarationCS.ast.type = if typeCS->notEmpty() then typeCS.ast else null endif In 9.3 OclMessageExpCS replace in OclMessageExpCS.ast.calledOperation = if operation->isEmpty() then OclUndefined else = operation endif OclMessageExpCS.ast.sentSignal = if signal->isEmpty() then OclUndefined else signal endif by in OclMessageExpCS.ast.calledOperation = if operation->isEmpty() then invalid else = operation endif OclMessageExpCS.ast.sentSignal = if signal->isEmpty() then invalid else signal endif In 9.4.3 final clause replace post: if self.namespace->notEmpty() -- this namespace has an owning namespace then result.parent = self.namespace.getEnvironmentWithParents() else result.parent = OclUndefined endif by post: if self.namespace->notEmpty() -- this namespace has an owning namespace then result.parent = self.namespace.getEnvironmentWithParents() else result.parent = invalid endif In 11.2.3 OclVoid replace The type OclVoid is a type that conforms to all other types except OclInvalid. It has one single instance, identified as null, that corresponds with the UML LiteralNull value specification. Any property call applied on null results in OclInvalid, except for the operation oclIsUndefined(). Any property call applied on null results in OclInvalid, except for the operation oclIsUndefined() and oclIsInvalid(). by The type OclVoid is a type that conforms to all other types except OclInvalid. It has one single instance, identified as null, that corresponds with the UML LiteralNull value specification. Any property call applied on null results in invalid, except for the oclIsUndefined(), oclIsInvalid(), =(OclAny) and <>(OclAny) operations. In 11.2.4 OclInvalid replace The type OclInvalid is a type that conforms to all other types except OclVoid. It has one single instance, identified as invalid. Any property call applied on invalid results in OclInvalid, except for the operations oclIsUndefined() and oclIsInvalid(). by The type OclInvalid is a type that conforms to all other types. It has one single instance, identified as invalid. Any property call applied on invalid results in invalid, except for the oclIsUndefined() and oclIsInvalid() operations. In 11.2.5 oclIsUndefined replace Evaluates to true if the self is equal to OclInvalid or equal to null. by Evaluates to true if the self is equal to invalid or equal to null. In 11.2.6 result replace Otherwise the undefined value is returned. by Otherwise the invalid value is returned. Change 11.2.5 Operations and Well-formedness Rules OclAny ... OclVoid= ... 11.2.6 OclMessage to 11.3 Operations and Well-formedness Rules 11.3.1 OclAny ... 11.3.2 OclVoid ... 11.3.3 OclMessage Move from 11.2.5 OclVoid = (object : OclAny) : Boolean Redefines the OclAny operation, returning true if object is null. post: result = object.oclIsTypeOf(OclVoid) to 11.3.2 OclVoid = (object : OclAny) : Boolean Redefines the OclAny operation, returning true if object is null. post: result = object.oclIsTypeOf(OclVoid) Remove from 11.2.5 OclInvalid = (object : OclAny) : Boolean Redefines the OclAny operation, returning true if object is invalid. post: result = object.oclIsTypeOf(OclInvalid) In 11.5.1 Real / replace Evaluates to OclInvalid if r is equal to zero. by Evaluates to invalid if r is equal to zero. In 11.5.2 Integer / replace Evaluates to OclInvalid if r is equal to zero. by Evaluates to invalid if r is equal to zero. In 11.7.1 Collection flatten replace [1] A collection cannot contain OclInvalid values. by [1] A collection cannot contain invalid values. In 12.12 paragraph 5 replace If more than one classifier is found, the operation returns OclUndefined. by If more than one classifier is found, the operation returns invalid. In A.1.1.1 replace All type domains include an invalid and a null value that allows one to operate respectively with unknown and “null” values. by All type domains include ?, an invalid value, and e, a null value, that allows one to operate respectively with invalid and undefined values. In A.1.1.2 Definition A.1 replace The main difference between classes and object types is that the interpretation of the latter includes a special undefined value. by The main difference between classes and object types is that the interpretation of the latter includes a special undefined value and a special invalid value. (OCL 2.0 typo) In A.1.1.5 Definition A.4 replace (sa) = <? c, c> by (sa) = <c, c> (OCL 2.0 typo) In A.1.1.6 Definition A.7 replace three uses of in the bottom line of the parents: definition by unicode 227A ? OCL 2.0 typo) Following A.1.1.6 Definition A.7 replace in the bottom line of the parents: definition by unicode 227A ? (OCL 2.0 typo) Following A.1.1.6 Definition A.8 point 3 replace by unicode 22C2 ? (OCL 2.0 typo) In A.1.1.7 Definition A.9 replace one use of and one use of by unicode 227A ? and M (OCL 2.0 typo) Following A.1.1.7 Definition A.9 point v. replace one use of by unicode 227A ? (OCL 2.0 typo) In A.1.2.1 remove (OCL 2.0 typo) In A.1.2.1 Definition A.10 restore the last equation to The domain of a class c Î CLASS is defined as ICLASS (c') = ?{oid(c') | c' Î CLASS ^ c' ? c} (OCL 2.0 typo) In A.1.2.2 restore the equation to " c1,c2 Î CLASS : c1 ? c2 ? I(c1) ? I(c2) . (OCL 2.0 typo) In A.1.2.3 Definition A.11 restore the last equation to Ias Î IASSOC(as). In A.2.1 Definition A.14 replace • I(Integer) = Z ? {?} • I(Real) = R ? {?} • I(Boolean) = { true, false } ? {?} • I(String) = A* ? {?} by • I(OclInvalid) = {?} • I(OclVoid) = {e,?} • I(Integer) = Z ? {e,?} • I(Real) = R ? {e,?} • I(Boolean) = { true, false } ? {e,?} • I(String) = A* ? {e,?} • I(UnlimitedNatural) = N ? {8,e,?} Following A.2.1 Definition A.14 replace Each domain also contains a special undefined value that is motivated in the next section. by Each domain also contains two special values e and ?. e coresponds to the null value, and ?, pronounced bottom, corresponds to the invalid value. These are motivated in the next section. In A.2.1.1 replace Each domain of a basic type t contains a special value ?. This value represents an undefined value that is useful for two purposes: 1. An undefined value may, for example, be assigned to an attribute of an object. ... 2. An undefined value can signal an error in the evaluation of an expression. ... The problems with partial functions can be eliminated by including an undefined value ? into the domains of types. ... ... Hence, an undefined argument value causes an undefined operation result. ... by Each domain of a basic type t contains two special values e and ?. e represents an null or undefined value and ? an invalid value. These are useful for the following purposes: 1. An undefined or null value may, for example, be assigned to an attribute of an object. ... 2. An invalid value can signal an error in the evaluation of an expression. ... The problems with partial functions can be eliminated by including the invalid value ? into the domains of types. ... ... Hence, an invalid or null argument value causes an invalid operation result. ... Following A.2.1.4 Definition A.16 replace I ?+??i1 , i2?={i1 + i2 if i1?? and i2?? ? otherwise by I ?+??i1 , i2?={i1 + i2 if i1?? and i1?e and i1?8 and i2?? and i2?e and i2?8 ? otherwise (NB. unlimited 8 is part of the resolution of the missing UnlimitedNatural specification). Replace A2.1.4 Table A.2 b1 b2 b1 and b2 b1 or b2 b1 xor b2 b1 implies b2 not b2 FALS E FALS E FALSE FALSE FALSE TRUE TRUE FALS E TRUE FALSE TRUE TRUE TRUE TRUE TRUE FALS E FALSE TRUE TRUE FALSE FALSE TRUE TRUE TRUE TRUE FALSE TRUE FALSE FALS E ? FALSE ? ? TRUE TRUE TRUE ? ? TRUE ? ? FALSE ? FALS E FAUX ? ? ? ? ? TRUE ? TRUE ? VRAI ? ? ? ? ? ? ? ? by b1 b2 b1 and b2 b1 or b2 b1 xor b2 b1 implies b2 not b2 FALSE FALS E FALSE FALSE FALSE TRUE TRUE FALSE TRUE FALSE TRUE TRUE TRUE TRUE TRUE FALS E FALSE TRUE TRUE FALSE FALSE TRUE TRUE TRUE TRUE FALSE TRUE FALSE FALSE ? or e FALSE ? ? TRUE TRUE TRUE ? or e ? TRUE ? ? FALSE ? or e FALS E FALSE ? ? ? ? ? or e TRUE ? TRUE ? TRUE ? ? or e ? or e ? ? ? ? ? (Only change is introduction of "or e" to the first two columns.) In A.2.2 replace I ?=t ??v1 , v2?={true if v1=v2, and v1?? and v2?? ? if v1=? or v2=? false otherwise by I ?=t ??v1 , v2?={true if v1=v2 and v1?? and v1?e and v1?8 and v2?? and v2?e and v2?8 true if v1=8 and v2=8 true if v1=e and v2=e ? if v1=? or v2=? false otherwise In A.2.2 replace It is also useful to have an operation that allows one to check whether an arbitrary value is well defined or undefined. This can be done with the operations isDefined t : t ? Boolean and isUndefinedt : t ? Boolean for any type t Î T. The semantics of these operations is given for any v Î I(t) by: I(isDefinedt)(v) = (v ? ? ) I(isUndefinedt )(v) = (v = ?) by It is also useful to have an operation that allows one to check whether an arbitrary value is invalid or undefined. This can be done with the operations oclIsInvalidt : t ? Boolean and oclIsUndefinedt : t ? Boolean for any type t Î T. The semantics of these operations is given for any v Î I(t) by: I(oclIsInvalidt)(v) = (v = ?) I(oclIsUndefinedt)(v) = (v = ?) ? (v = e) In A.2.3 Definition A.18 replace I(t) = literals(t) ? {?}. by I(t) = literals(t) ? {e,?}. In A.2.4 Definition A.20 replace I(t) = ICLASS(c) ? {?}. by I(t) = ICLASS(c) ? {e,?}. In A.2.4 Following Definition A.20 replace The undefined value that is only available with the type by The undefined null value that is only available with the type In A.2.4 Following Definition A.20 replace Otherwise, the result is the undefined value. by Otherwise, the result is the invalid value. In A.2.4.3 Following Definition A.21 replace The attempt to access an attribute of a non-existent object results in an undefined value. by The attempt to access an attribute of a non-existent object results in the invalid value. (OCL 2.0 typo) In A.2.4.5 restore the first equation to M = (CLASS, ATTc, OPc, ASSOC, associates, roles, multiplicities, ?). In A.2.5.4 last paragraph replace A collection value therefore may contain undefined values while still being well defined. by A collection value therefore may contain undefined null values while still being well defined. (OCL 2.0 typo) In A.2.5.5 following Table A.3 restore the first equation to Set(t) X t ? Integer In A.2.5.5 following I(count) replace A set may contain the undefined value so that the result of count is 1 if the undefined value is passed as the second argument, for example, count({?}, ?) = 1 and count({1}, ?) = 0. by A set may contain the undefined null value so that the result of count is 1 if the null value is passed as the second argument, for example, count({e}, e) = 1 and count({1}, e) = 0. In A.2.6 replace • OclVoid is the subtype of all other types. The only value of this type is the undefined value. Notice that there is no problem with cyclic domain definitions as ? is an instance of every type. by • OclVoid is the subtype of all types other than OclVoid and OclInvalid. The only value of this type is null, the undefined value. Notice that there is no problem with cyclic domain definitions as e is an instance of every type other than OclInvalid. • OclInvalid is the subtype of all other types. The only value of this type is invalid, the invalid value. Notice that there is no problem with cyclic domain definitions as ? is an instance of every type. In A.2.6.1 replace The set of special types is TS = {OclAny, OclVoid}. Let ^ T be the set of basic, enumeration, and object types ^ T = TB U TE U TC . The domain of OclAny is given as I(OclAny) = (UteT I(t)) U {?}. The domain of OclVoid is I(OclVoid) = {?}. by The set of special types is TS = {OclAny, OclVoid, OclInvalid}. Let T^ be the set of basic, enumeration, and object types T^ = TB U TE U TC . The domain of OclAny is given as I(OclAny) = (UteT I(t)) U {e,?}. The domain of OclVoid is I(OclVoid) = {e,?}. The domain of OclInvalid is I(OclInvalid) = {?}. In A.2.6.1 replace For OclVoid, the constant operation undefined : ? OclVoid results in the undefined value ?. The semantics is given by I(undefined) = ?. by For OclVoid and OclInvalid, the constant operation oclIsUndefined : ? Boolean results in the true value, and for OclInvalid, the constant operation oclIsInvalid : ? Boolean results in the true value. The semantics is given by I(OclVoid) = {e,?} and I(OclInvalid) = ?. In A.2.7 add ?. OclInvalid is a subtype of OclVoid. In A.2.7 replace 4. OclVoid is subtype of all other types. by 4. OclVoid is subtype of all types other than OclVoid and OclInvalid. In A.2.7 Definition A.27 add ?. OclInvalid = OclVoid. (OCL 2.0 typo) In A.2.7 Definition A.27 restore viii to viii. If classOf(t’c) ? classOf(tc) then t’c = tc. In A.3.1.2 above the if then else example replace An undefined condition makes the whole expression undefined. Note that when an expression in one of the alternative branches is undefined, by A null or invalid condition makes the whole expression invalid. Note that when an expression in one of the alternative branches is null or invalid, In A.3.1.2 after the if then else example replace The result of a cast expression (vi) using asType is the value of the expression, if the value lies within the domain of the specified target type, otherwise it is undefined. ... Note that these type cast and test expressions also work with undefined values since every value – including an undefined one – has a welldefined type. by The result of a cast expression (vi) using asType is the value of the expression, if the value lies within the domain of the specified target type, otherwise it is invalid. ... Note that these type cast and test expressions also work with null or invalid values since every value – including a null or invalid one – has a welldefined type. In A.3.1.5 last sentence replace Invariants with undefined result invalidate a system state. by Invariants with null or invalid result invalidate a system state. In A.3.2.1 three bullets from the end replace Hence, a reference to the previous value of attribute c is undefined. by Hence, a reference to the previous value of attribute c is invalid. In A.3.2.2 Definition A.32 second bullet replace Output parameters are undefined on entry: kind(p) = out implies ßpre(p) = ?. by Output parameters are null on entry: kind(p) = out implies ßpre(p) = e. Disposition: Resolved OMG Issue No: 14199 Title: Inaccurate well-formedness constraints for IteratorExp Source: THALES (Dr. Edward Willink, ed.willink@thalesgroup.com ed@willink.me.uk) Summary: The well-formedness constraints for IteratorExp are confusing, incomplete and sometimes wrong. For instance it is specified in words that for 8.3.7 IteratorExp [1] the iterator of forAll is Boolean. The subsequent constraint is correct; it is the iteration type not iterator that is Boolean. 8.3.7 IteratorExp[2] uses a non-existent property collectionType and selects the first of a number of body type returns. This seems to confuse dynamic and static behaviours.. 8.3.7 IteratorExp[4] uses boolean rather than Boolean and tests only for the name and not the meta class. The only one iterator allowed constraint is missing. There are no constraints for any, collectNested, one, sortedBy. The presentation in Section 8.3.5 is unhelpful through bundling the various iterator semantics under a single heading. Multiple headings such as IteratorExp forAll would be more readable for the full set of iterators.. Discussion: The revised text below resolves these issues. Revised Text: In 8.3.7 replace IteratorExp [1] If the iterator is ‘forAll,’ ‘isUnique,’ or ‘exists’ the type of the iterator must be Boolean. Actions taken: August 22, 2009: received issue April 25, 2011: closed issue Discussion: The resolution of Issue 6611 is wrong. OclAny=(object : OclAny) should not be overloaded for OclInvalid. The resolution violates the principle that invalid results should propagate arithmetically unless explicitly tested using oclIsInvalid() or oclIsUndefined(). The danger of this is clear from the following example: let expr1 : Boolean = eval1() in let expr2 : Boolean = eval2() in expr1 = expr2 If both eval1() and eval2() fail and return invalid, the overall result subject to the Issue 6611 resolution is true. The result must be invalid to propagate invalid. The resolutions of Issue 10433, 10434, 12378, 12484, 12485 are wrong. OclInvalid should remain conformant to OclVoid. None of the resolutions address the massive conflict between Section 8 and Section 11. While neither section is close to self consistent, Section 8 strongly suggests that OclInvalid is the instance of Invalid which is the instance of InvalidType, while Section 11 almost mandates that invalid is the instance of OclInvalid which is the instance of InvalidType. The resolution of Issue 12349 is locally unhelpful through referring to invalid as unknown and totally inadequate to address the issue of two bottoms throughout the remaining text. There is probably little practical difference between the alternative conformance choices for OclVoid and OclInvalid, however the text should be consistent. The original 2.0 Appendix A is sensibly interpreted with bottom (?) equated to invalid. It is just necessary to introduce and equate a nearly-bottom (e) as null and align all the text accordingly. End of Annotations:===== iler: QUALCOMM Windows Eudora Version 7.1.0.9 Date: Mon, 24 Aug 2009 13:31:43 -0400 To: issues@omg.org, ocl2-rtf@omg.org From: Juergen Boldt Subject: issue 14197 -- OCL 2 RTF issue X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: ApoEAHXqj0rUnw6U/2dsb2JhbADDDI9KhBoF Date: Sat, 22 Aug 2009 20:56:32 +0100 From: Ed Willink User-Agent: Thunderbird 2.0.0.23 (Windows/20090812) To: issues@omg.org Subject: OCL 2.0, 2.1 inconsistent definition of null and invalid X-Plusnet-Relay: 249d3cbac08b491177dcfedeac1573df Hi The attached surprisingly large set of revised text recommendations endeavours to resolve every inconsistent use of invalid and null/void types and the failure to update the specification when undefined was split into null and invalid. The recommendations also correct many conversion errors that crept in when Word Processor formats were changed. Once these changes are incorporated, a very careful proof read against at least Annex A of 03-01-07 should be performed. The initial discussion identifies that the approved resolutions of Issues: 6611, 10433, 10434, 12349, 12378, 12484 and 12485 are at best deficient. Regards Ed Willink NullAndInvalid.odt Juergen Boldt Director, Member Services Object Management Group 140 Kendrick St Building A Suite 300 Needham, MA 02494 USA tel: +1 781 444 0404 x 132 fax: +1 781 444 0320 email: juergen@omg.org www.omg.org X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: ApoEAFuQzErUnw4U/2dsb2JhbADXIoQqBA Date: Wed, 07 Oct 2009 20:58:49 +0100 From: Ed Willink User-Agent: Thunderbird 2.0.0.22 (Windows/20090605) To: "'ocl2-rtf@omg.org'" Subject: Re: Issue 14197: OCL 2.0, 2.1 inconsistent definition of null and invalid X-Plusnet-Relay: 99d8c43cb9bddf2e5812b6abd6c4322f Hi Since null is an absence of value, rather than a failure, null should have rather more behaviour: For instance surely null.oclIsTypeOf(OclVoid) is true and null.oclIsKindOf(Boolean) is true and null.oclAsType(String) is null? e.g. in Java; (String)null is perfectly reasonable. Anyone in favour of revising the earlier attachment to add the above functions for OclVoid? Regards Ed Willink From: "Brucker, Achim" To: "'ocl2-rtf@omg.org'" Date: Thu, 8 Oct 2009 06:18:20 +0200 Subject: RE: Issue 14197: OCL 2.0, 2.1 inconsistent definition of null and invalid Thread-Topic: Issue 14197: OCL 2.0, 2.1 inconsistent definition of null and invalid Thread-Index: AcpHiMojx8ATD6bPT6G+9arBn+Zu6wARPICw Accept-Language: en-US, de-DE X-MS-Has-Attach: X-MS-TNEF-Correlator: acceptlanguage: en-US, de-DE X-Scanner: Virus Scanner virwal08 X-SAP: out X-MIME-Autoconverted: from quoted-printable to 8bit by amethyst.omg.org id n984GlIQ007247 Hi, > > Since null is an absence of value, rather than a failure, null should > have rather more behaviour: > > For instance surely > > null.oclIsTypeOf(OclVoid) > > is true and > > null.oclIsKindOf(Boolean) > > is true and > > null.oclAsType(String) > > is null? > > e.g. in Java; (String)null is perfectly reasonable. > > Anyone in favour of revising the earlier attachment to add the above > functions for OclVoid? I think it is a good idea to explicitly mention in the standard, that the type/kind tests and casts are also features that can be called on "null" without resulting in a failure. We also came to similar conclusions in a paper that was recently presented at the OCL Workshop: http://www.brucker.ch/bibliography/abstract/brucker.ea-ocl-null-2009.en.html Achim X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: ApoEADcd+krUnw4S/2dsb2JhbADcLYQ8BA Date: Wed, 11 Nov 2009 10:15:07 +0000 From: Ed Willink User-Agent: Thunderbird 2.0.0.23 (Windows/20090812) To: "'ocl2-rtf@omg.org'" Subject: Re: Issue 14197 inconsistent definition of null and invalid X-Plusnet-Relay: 30af252fe7cedeb841f3578563c1f85c Hi The attached replaces the earlier attachment with the original Issue. Regards Ed Willink