<?xml version="1.0" encoding="UTF-8"?>
<TEI xml:space="preserve" xmlns="http://www.tei-c.org/ns/1.0" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="http://www.tei-c.org/ns/1.0 https://raw.githubusercontent.com/kermitt2/grobid/master/grobid-home/schemas/xsd/Grobid.xsd"
 xmlns:xlink="http://www.w3.org/1999/xlink">
	<teiHeader xml:lang="en">
		<fileDesc>
			<titleStmt>
				<title level="a" type="main">Safe Navigation in OCL</title>
			</titleStmt>
			<publicationStmt>
				<publisher/>
				<availability status="unknown"><licence/></availability>
			</publicationStmt>
			<sourceDesc>
				<biblStruct>
					<analytic>
						<author>
							<persName><forename type="first">Edward</forename><forename type="middle">D</forename><surname>Willink</surname></persName>
							<affiliation key="aff0">
								<orgName type="institution">Willink Transformations Ltd</orgName>
								<address>
									<settlement>Reading</settlement>
									<region>England</region>
								</address>
							</affiliation>
						</author>
						<title level="a" type="main">Safe Navigation in OCL</title>
					</analytic>
					<monogr>
						<imprint>
							<date/>
						</imprint>
					</monogr>
					<idno type="MD5">7CFFC65BA8515FBB6DC0DC261E93FF7F</idno>
				</biblStruct>
			</sourceDesc>
		</fileDesc>
		<encodingDesc>
			<appInfo>
				<application version="0.7.2" ident="GROBID" when="2023-03-24T23:33+0000">
					<desc>GROBID - A machine learning software for extracting information from scholarly documents</desc>
					<ref target="https://github.com/kermitt2/grobid"/>
				</application>
			</appInfo>
		</encodingDesc>
		<profileDesc>
			<textClass>
				<keywords>
					<term>OCL</term>
					<term>safe navigation</term>
					<term>multiplicity</term>
					<term>non-null</term>
					<term>null-free</term>
				</keywords>
			</textClass>
			<abstract>
<div xmlns="http://www.tei-c.org/ns/1.0"><p>The null object has been useful and troublesome ever since it was introduced. The problems have been mitigated by references in C++, annotations in Java or safe navigation in Groovy, Python and Xbase. Introduction of a safe navigation operator to OCL has some rather unpleasant consequences. We examine these consequences and identify further OCL refinements that are needed to make safe navigation useable.</p></div>
			</abstract>
		</profileDesc>
	</teiHeader>
	<text xml:lang="en">
		<body>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="1">Introduction</head><p>Tony Hoare apologized in 2009 <ref type="bibr" target="#b2">[3]</ref> for inventing the null reference in 1965. This 'billion dollar mistake' has been causing difficulties ever since. However NIL had an earlier existence in LISP and I'm sure many of us would have made the same mistake.</p><p>The problem arises because the null object has many, but not all, of the behaviors of an object and any attempt to use one of the missing behaviors leads to a program failure. Perhaps the most obvious missing behavior is used by the navigation expression anObject.name which accesses the name property of anObject. Whenever anObject can be null, accessing its name property can cause the program to fail.</p><p>A reliable program must avoid all navigation failures and so must prove that the source object of every navigation expression is never null. This is often too formidable an undertaking. We are therefore blessed with many programs that fail due to NullPointerException when an unanticipated control path is followed.</p><p>Language enhancements such as references <ref type="bibr" target="#b1">[2]</ref> in C++ allow the non-nullness of objects to be declared as part of the source code. Once these are exploited by good programmers, compile-time analysis can identify a tractably small number of residual navigation hazards that need to be addressed.</p><p>A similar capability is available using @NonNull <ref type="bibr" target="#b4">[5]</ref> annotations in Java, however problems of legacy compatibility for Java's large unannotated libraries makes it very hard to achieve comprehensive detection of null navigation hazards.</p><p>An alternative approach is pursued by languages such as Groovy <ref type="bibr" target="#b3">[4]</ref>, Python <ref type="bibr" target="#b7">[8]</ref> and Xbase <ref type="bibr">[10]</ref>. A safe navigation operator makes the nulls less dangerous so that anObject?.name avoids the failure if anObject is null. The failure is replaced by a null result which may solve the problem, or may just move the problem sideways since the program must now be able to handle a null name.</p><p>In this paper we consider how OCL can combine the static rigor of C++-like references with the dynamic convenience of a safe navigation operator. In Section 2 we introduce the safe navigation operators to OCL and identify that their impact may actually be detrimental. We progressively remedy this in Section 3 by introducing non-null object declarations, null-free collection declarations, nullsafe libraries, null-safe models and consider the need for a deep non-null analysis. Finally we briefly consider related work in Section 4 and conclude in Section 5.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="2">Safe Navigation Operators</head><p>OCL 2.4 <ref type="bibr" target="#b6">[7]</ref> has no protection against the navigation of null objects; any such navigation yields an invalid value. This is OCL's way of accommodating a program failure that other languages handle as an exception. OCL provides powerful navigation and collection operators enabling compact expressions such as aPerson.father.name.toUpper() This obviously fails if aPerson is null. It also fails whenever father is null as may be inevitable in a finite model. A further failure is possible if name is null as may happen for an incomplete model.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="2.1">Safe Object Navigation Operator</head><p>We can easily introduce the safe object navigation operator ?. to OCL by defining x?.y as a short-form for if x &lt;&gt; null then x.y else null endif We can rewrite aPerson.father.name.toUpper() for safety as aPerson?.father?.name?.toUpper() This ensures that the result is the expected value or null; no invalid failure.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="2.2">Safe Collection Navigation Operator</head><p>Collection operations are a very important part of OCL and any collection navigation such as aPerson.children-&gt;collect(name) will fail if any element of the children collection is null.</p><p>We can easily introduce the safe collection navigation operator ?-&gt; to OCL by defining x?-&gt;y as a short-form for</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head>x-&gt;excluding(null)-&gt;y</head><p>We can rewrite the problematic collection navigations for safety as:</p><formula xml:id="formula_0">aPerson?.children?-&gt;collect(name)</formula><p>This ensures that any null children are ignored and so do not cause an invalid failure.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="2.3">Safe Implicit-Collect Navigation Operator</head><p>The previous example is the long form of explicit collect and so could be written more compactly as:</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head>aPerson.children.name</head><p>The long form of the ?. operator in x?.y is therefore</p><p>x-&gt;excluding(null)-&gt;collect(y)</p><p>We can rewrite for safety as aPerson?.children?.name This again ensures that null children are ignored.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="2.4">Assessment</head><p>OCL 2.4 already has distinct object and collection navigation operators, with implicit-collect and implicit-as-set short-forms. These are sufficient to confuse new or less astute OCL programmers, who may just make a random choice and hope for a tool to correct the choice. Adding a further two operators can only add to the confusion. We must therefore look closely at how tooling can exploit the rigor of OCL to ensure that safe navigation usefully eliminates the null value fragility.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="2.5">Safe Navigation Validation</head><p>The safe navigation operators should assist in eliminating errors and the following tentative Well Formedness Rules can identify an appropriate choice.</p><p>Error: Safe Navigation Required. If the navigation source could be null, a safe navigation operator should be used to avoid a run-time hazard.</p><p>Warning: Safe Navigation not Required. If the navigation source cannot be null, a safe navigation operator is unnecessary and may incur run-time overheads.</p><p>The critical test is could-be-null / cannot-be-null. How do we determine this for OCL? Some expressions such as constants 42 or Set{true} are inherently not null. These can contribute to a program analysis so that a compound expression such as if ... then Set{42} else Set{} endif is also non-null even though we may not know anything about the if-condition. Unfortunately, OCL permits any object to be null and so all accesses to objects can be null. In practice this means that most OCL expressions cannot be usefully analyzed and the validation WFRs will just force users to write ?. everywhere just to silence the irritating errors.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="3">Non-null declarations</head><p>We have seen how the safe navigation operator is unuseably pessimistic when non-null objects cannot be usefully identified. We will therefore examine how to identify such objects.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="3.1">Non-null Object declarations</head><p>We could consider introducing non-null declarations analogous to C++ reference declarations. We could even re-use the &amp; character. But we don't need to, since UML <ref type="bibr" target="#b8">[9]</ref> already provides a solution and a syntax. When declaring a TypedElement, a multiplicity may qualify the type: mandatoryName : String <ref type="bibr" target="#b0">[1]</ref> optionalName : String[?]</p><p>[?] indicates that a String value is optional; a null value is permitted. <ref type="bibr" target="#b0">[1]</ref> indicates that a String value is required; a null value is prohibited. (Other multiplicities such as [*] are not appropriate for a single object.). OCL can exploit this information coming from UML models and may extend the syntax of iterators, let-variables and tuple parts to support similar declarations in OCL expressions. However, since OCL has always permitted nulls, we must treat [?] as the default for the extended OCL declarations even though <ref type="bibr" target="#b0">[1]</ref> is the default for UML declarations.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="3.2">Null-free Collection declarations</head><p>The ability to declare non-null variables and properties provides some utility for safe navigation validation, but we soon hit another problem. Collection operations are perhaps the most important part of OCL, and any collection may contain none, some or many null elements. Consequently whenever we operate on collection elements we hit the pessimistic could-be-null hazard.</p><p>Null objects can often be useful. However collections containing null are rarely useful. The pessimistic could-be-null hazards are therefore doubly annoying for collection elements:</p><p>-a large proportion of collection operations are diagnosed as hazardous -the hazard only exists because the tooling fails to understand typical usage.</p><p>In order to eliminate the hazard diagnosis, we must be able to declare that a collection is null-free; i.e. that it contains no null elements. This could be treated as a third boolean qualifier extending the existing ordered and unique qualifiers. We could therefore introduce the new names, NullFreeBag, NullFreeCollection, NullFreeOrderedSet, NullFreeSequence and NullFreeSet but this is beginning to incur combinatorial costs.</p><p>A different aspect of UML provides an opportunity for extension. UML supports bounded collections, but OCL does not, even though OCL aspires to UML alignment. The alignment deficiency can be remedied by following a collection declaration by an optional UML multiplicity bound. Thus Set(String) is a short-form for Set(String)[0..*] allowing UML bounded collections and OCL nested collections to support e.g. Sequence(Sequence(Integer) <ref type="bibr" target="#b2">[3]</ref>) <ref type="bibr" target="#b2">[3]</ref> as the declaration of a 3*3 Integer matrix.</p><p>However, this UML collection multiplicity tells us nothing about whether elements cannot-be-null. We require an extension of the UML collection multiplicity to also declare an element multiplicity. Syntactically we can re-use the vertical bar symbol to allow [x|y] to be read as 'a collection of multiplicity x where each element has multiplicity y'. We can now prohibit null elements and null rows by specifying Sequence(Sequence(Integer</p><formula xml:id="formula_1">)[3|1])[3|1].</formula><p>Finally, we are getting somewhere. A collection operation on a null-free collection obviously has a non-null iterator and so the known non-null elements can propagate throughout complex OCL expressions. Provided we use accurate non-null and null-free declarations in our models, well-written OCL that already avoids null hazards does not need any change. Less well written OCL has its null hazards diagnosed.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="3.3">Null-safe libraries</head><p>The OCL standard library provides a variety of useful operations and iterations. Their return values may or may not be non-null. The library currently has only semi-formal declarations. These lack the precision we need for null-safe analysis. We will therefore consider how more formal declarations can capture the behaviors that we need to specify.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head>Simple Declaration Consider the declaration</head></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head>String::toBoolean() : Boolean</head><p>Using the default legacy interpretation that anything can be null, this should be elaborated as</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head>String::toBoolean() : Boolean[?]</head><p>But we have an additional postcondition:</p><formula xml:id="formula_2">post: result = (self = 'true')</formula><p>Intuitively this assures a true/false result. But we must always consider null and invalid carefully. If self is null, the comparison using OclAny::= returns false, and if self is invalid the result is invalid. We are therefore able to provide a stronger backward compatible library declaration that guarantees a non-null result.</p><p>String::toBoolean() : Boolean <ref type="bibr" target="#b0">[1]</ref> We can pursue similar reasoning to provide [?] and <ref type="bibr" target="#b0">[1]</ref> throughout the standard library.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head>Complex Declaration</head><p>We hit problems where the non-null-ness/null-free-ness of a result is dependent on the non-null-ness/null-free-ness of one or more inputs.</p><p>Consider a declaration for Set::including in which we use parameters such as T1, c1, e1 to represent flexibilities that we may need to constrain.</p><formula xml:id="formula_3">Set(T1)[c1|e1]::including(T2)(x2 : T2[e2]) : Set(T3)[c3|e3]</formula><p>The relationship between T1, T2 and T3 is not clear in the current OCL specification. Some implementations emulate Java-style collection declarations where the result is the modified input; T3 is therefore the same as T1, and T2 must be assignable to T1. This implementation-driven restriction is not necessary for a declarative specification language such as OCL where we just require that each of T1 and T2 are assignable to T3. The declarative flexibility can be captured by a single type parameter and a direction that the most derived solution be selected from the many possible solutions.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head>Set(T)[c1|e1]::including(x2 : T[e2]) : Set(T)[c3|e3]</head><p>The result is only null-free if the input collection is null-free and the additional value is non-null. Therefore if e1 and e2 are Boolean-valued with true for <ref type="bibr" target="#b0">[1]</ref> (is not null) and false for [?] (may be null), e3 may be computed as:</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head>e3 = e1 and e2</head><p>This computation can be included in a library model to avoid the need for an implementation to transliterate specification words into code.</p><p>We can also compute c3 pessimistically as c3.lower = c1.lower c3.upper = if c1.upper = * then * else c1.upper+1 endif Preliminary discussions at Aachen <ref type="bibr" target="#b0">[1]</ref> indicated limited enthusiasm for accurate modeling of collection bounds in OCL, so we could just take the view that OCL does not support bounded collections enthusiastically; The definition of c3 is then much simpler: c3.lower = 0 c3.upper = * However if we need accurate equations to avoid loss of non-null-ness precision for library operations, the simplification of not providing similar equations for collection bounds may prove to be a false saving.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="3.4">Null-safe models</head><p>Once the standard library has accurate null-safe modeling we are just left with the problem of user models.</p><p>For object declarations, there seems little choice but to make this part of the user's modeling discipline; object declarations must accurately permit or prohibit the use of null.</p><p>For collection declarations the default may-be-null legacy behavior is mostly wrong and for some users it may be universally wrong. We would like to provide a universal change to the default so that all collections are null-free unless explicitly declared to be null-full. In UML, we can achieve this by defining an OCL::Collections::nullFree stereotype property for a Package or Class. The nullFree Boolean property provides a setting that is 'inherited' by all collectionvalued properties within the Package or Class.</p><p>UML has no support for declaring collection elements to be non-null, so we need a further OCL::Collection::nullFree stereotype property to define whether an individual TypedElement has a null-free collection or not.</p><p>For disciplined modelers, the sole cost of migrating to null-safe OCL will be to apply an OCL::Collections stereotype to each of their Packages.</p><p>Feedback from workshop UML is moving, and perhaps has already moved, to prohibit nulls in multi-valued properties. UML-derived collections are therefore inherently null-free and no stereotype is required. Rather the converse of a nullfull declaration is needed to declare that nulls are really required and that some workaround for the UML prohibition is to be used.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="3.5">Deep non-null analysis</head><p>Accurate non-null declarations enable WFRs to diagnose null navigation hazards ensuring that safe navigation is used when necessary. However simple WFRs provide pessimistic analysis.</p><p>For instance, the anObject.name navigation in the following example is safe since it is guarded by anObject &lt;&gt; null let anObject : NamedElement[?] = .... in anObject &lt;&gt; null implies anObject.name &lt;&gt; null However a simple WFR using just anObject : NamedElement[?] diagnoses a lack of safety because the anObject let-variable may be null. A potentially exponential program flow analysis is needed to eliminate all possible false unsafe diagnostics. A simpler pragmatic program flow analysis can eliminate the common cases of an if/implies/and non-null guard.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="4">Related Work</head><p>The origin and long history of null problems has been alluded to in the introduction as has the mitigation for C++ and Java.</p><p>The safe navigation operator is not new since at least Groovy, Python and Xbase provide it.</p><p>The database usage of NULL as an absence of value is in principle similar to OCL's use of null, however whereas use of null in OCL leads to failures, SQL is more forgiving. This can be helpful, but also hazardous.</p><p>The possibility of safe navigation in OCL is new, or rather the pair of ?. and ?-&gt; operators were new when we suggested them at the Aachen workshop <ref type="bibr" target="#b0">[1]</ref>. The utility of the [?] and <ref type="bibr" target="#b0">[1]</ref> non-null multiplicities was also mentioned at the Aachen workshop. The null-free declarations, stereotypes and the interaction between safe navigation and non-null multiplicities have not been presented before, although they are available in the Mars release of Eclipse OCL <ref type="bibr" target="#b5">[6]</ref>.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="5">Conclusions</head><p>We find that naive introduction of safe navigation to OCL risks just doubling the number of arbitrary navigation operator choices for an unskilled OCL user. These problems are soluble with tool support provided we can also solve the problem of declaring non-null objects and null-free collections.</p><p>We take inspiration from UML multiplicity declarations to provide the necessary declarations. We use stereotypes for declarations that are not inherently supported by UML.</p><p>The cost for well-designed models may be as little as -one stereotype per Package to specify that all of its collections are null-free -an accurate [?] or <ref type="bibr" target="#b0">[1]</ref> multiplicity to encode the design intent of each noncollection Property</p><p>The benefit is that OCL navigation can be fully checked for null safety.</p></div>		</body>
		<back>

			<div type="acknowledgement">
<div xmlns="http://www.tei-c.org/ns/1.0"><p>Acknowledgments Many thanks to Adolfo Sánchez-Barbudo Herrera for his detailed review and constructive comments.</p></div>
			</div>

			<div type="references">

				<listBibl>

<biblStruct xml:id="b0">
	<analytic>
		<author>
			<persName><forename type="first">A</forename><surname>Brucker</surname></persName>
		</author>
		<author>
			<persName><forename type="first">D</forename><surname>Chiorean</surname></persName>
		</author>
		<author>
			<persName><forename type="first">T</forename><surname>Clark</surname></persName>
		</author>
		<author>
			<persName><forename type="first">B</forename><surname>Demuth</surname></persName>
		</author>
		<author>
			<persName><forename type="first">M</forename><surname>Gogolla</surname></persName>
		</author>
		<author>
			<persName><forename type="first">D</forename><surname>Plotnikov</surname></persName>
		</author>
		<author>
			<persName><forename type="first">B</forename><surname>Rumpe</surname></persName>
		</author>
		<author>
			<persName><forename type="first">E</forename><surname>Willink</surname></persName>
		</author>
		<author>
			<persName><forename type="first">B</forename><surname>Wolff</surname></persName>
		</author>
		<ptr target="http://ceur-ws.org/Vol-1092/aachen.pdf" />
	</analytic>
	<monogr>
		<title level="m">Report on the Aachen OCL Meeting</title>
		<title level="s">CEUR-WS Proceedings</title>
		<imprint>
			<date type="published" when="2013">2013</date>
			<biblScope unit="volume">1092</biblScope>
		</imprint>
	</monogr>
</biblStruct>

<biblStruct xml:id="b1">
	<monogr>
		<title level="m" type="main">The Annotated C++ Reference Manual</title>
		<author>
			<persName><forename type="first">M</forename><surname>Ellis</surname></persName>
		</author>
		<author>
			<persName><forename type="first">B</forename><surname>Stroutstrup</surname></persName>
		</author>
		<imprint>
			<date type="published" when="1990">1990</date>
		</imprint>
	</monogr>
</biblStruct>

<biblStruct xml:id="b2">
	<monogr>
		<title level="m" type="main">Null References: The Billion Dollar Mistake</title>
		<author>
			<persName><forename type="first">T</forename><surname>Hoare</surname></persName>
		</author>
		<imprint>
			<date type="published" when="2009">2009</date>
			<pubPlace>QCon London</pubPlace>
		</imprint>
	</monogr>
</biblStruct>

<biblStruct xml:id="b3">
	<analytic>
	</analytic>
	<monogr>
		<title level="m">The Groovy Programming Language</title>
				<imprint>
			<date type="published" when="2004">2004</date>
			<biblScope unit="volume">241</biblScope>
		</imprint>
	</monogr>
</biblStruct>

<biblStruct xml:id="b4">
	<monogr>
		<ptr target="http://help.eclipse.org/luna/index.jsp?topic=%2Forg.eclipse.jdt.doc.user%2Ftasks%2Ftask-using%5Fnull%5Fannotations.htm" />
		<title level="m">Using null annotations</title>
				<imprint/>
	</monogr>
</biblStruct>

<biblStruct xml:id="b5">
	<monogr>
		<ptr target="https://www.eclipse.org/modeling/mdt/downloads/?project=ocl" />
		<title level="m">Eclipse OCL</title>
				<imprint/>
	</monogr>
</biblStruct>

<biblStruct xml:id="b6">
	<analytic>
		<title level="a" type="main">Object Constraint Language</title>
		<ptr target="http://www.omg.org/spec/OCL/2.4" />
	</analytic>
	<monogr>
		<title level="m">OMG Document Number: formal/2014-02-03, Object Management Group</title>
				<imprint>
			<date type="published" when="2009">2009</date>
		</imprint>
	</monogr>
	<note>Version 2.4</note>
</biblStruct>

<biblStruct xml:id="b7">
	<monogr>
		<title level="m" type="main">Python Software Foundation: The Python Language Reference</title>
		<imprint>
			<date type="published" when="2015">2015</date>
			<biblScope unit="volume">2</biblScope>
			<biblScope unit="page">10</biblScope>
		</imprint>
	</monogr>
</biblStruct>

<biblStruct xml:id="b8">
	<monogr>
		<ptr target="http://www.omg.org/spec/UML/2.5" />
		<title level="m">OMG Unified Modeling Language (OMG UML), Version 2.5, OMG Document Number: formal/15-03-01, Object Management Group</title>
				<imprint>
			<date type="published" when="2015">2015</date>
		</imprint>
	</monogr>
</biblStruct>

				</listBibl>
			</div>
		</back>
	</text>
</TEI>
