<!DOCTYPE article PUBLIC "-//NLM//DTD JATS (Z39.96) Journal Archiving and Interchange DTD v1.0 20120330//EN" "JATS-archivearticle1.dtd">
<article xmlns:xlink="http://www.w3.org/1999/xlink">
  <front>
    <journal-meta>
      <journal-title-group>
        <journal-title>International Workshop on OCL and Textual Modeling, June</journal-title>
      </journal-title-group>
    </journal-meta>
    <article-meta>
      <title-group>
        <article-title>Implementing OCL in Swift</article-title>
      </title-group>
      <contrib-group>
        <contrib contrib-type="author">
          <string-name>K. Lano</string-name>
          <xref ref-type="aff" rid="aff0">0</xref>
        </contrib>
        <aff id="aff0">
          <label>0</label>
          <institution>Dept. of Informatics, King's College London</institution>
          ,
          <country country="UK">UK</country>
        </aff>
      </contrib-group>
      <pub-date>
        <year>2021</year>
      </pub-date>
      <volume>25</volume>
      <issue>2021</issue>
      <abstract>
        <p>Swift is the new programming language for Apple platforms such as MacOS and iOS, and it is the basis of the SwiftUI mobile app framework. The language incorporates first-class functions, open classes, and other advanced features. In this paper we describe a tool for translating UML and OCL specifications into fully-functional code in Swift. Translation of OCL extensions (map and function types) are also described.</p>
      </abstract>
      <kwd-group>
        <kwd>eol&gt;Object Constraint Language (OCL)</kwd>
        <kwd>Code generation</kwd>
        <kwd>Swift</kwd>
        <kwd>CSTL</kwd>
      </kwd-group>
    </article-meta>
  </front>
  <body>
    <sec id="sec-1">
      <title>1. Introduction</title>
    </sec>
    <sec id="sec-2">
      <title>2. Translation from OCL to Swift</title>
      <p>At a high level, the translation from UML+OCL to Swift can be defined as follows:
1. UML/OCL types are mapped to corresponding Swift types, with the exception that</p>
      <p>
        OclMessage and UnlimitedNatural are not mapped.
2. UML data features are mapped to Swift variables or constants of corresponding type and
scope (instance or class scope).
3. OCL expressions are mapped to corresponding Swift expressions, defined directly in
terms of Swift expression operators, or by using a library Ocl.swift which provides
implementations of OCL operators2. 101 OCL 2.4 library operators are supported by the
translation, out of 181 operators in [
        <xref ref-type="bibr" rid="ref11">11</xref>
        ].
4. The translation of UML activities to program statements is direct.
5. Operations and use cases map to Swift local and global functions.
6. UML class definitions map to Swift classes, with additional auxiliary variables and
operations to support use of the allInstances() operator.
      </p>
      <p>
        We describe the translation by using the  ℒ notation for code-generator specification
[
        <xref ref-type="bibr" rid="ref8">8</xref>
        ]. A  ℒ script defines a text-to-text code generator, and consists of a sequence of rules
grouped into source language syntax categories. Individual rules have the form:
selement |--&gt; telement &lt;when&gt; Condition
The &lt;when&gt; clause and condition are optional. The left hand side (LHS) of a  ℒ rule is
some piece of textual concrete syntax in the source language, e.g., in Kernel Metamodel (KM3)
[
        <xref ref-type="bibr" rid="ref5">5</xref>
        ] textual notation for UML class models, and the right hand side (RHS) is the corresponding
concrete syntax in the target language (e.g., C, Java, Swift, etc), which the LHS should translate
to. Apart from literal text concrete syntax, the LHS may contain variable terms 1, 2, etc,
representing arbitrary source concrete syntax fragments, and the RHS refers to the translation
of these fragments also by 1, 2, etc. Specialised rules are listed before more general rules. The
default translation (if no rule applies) is textual copying.
      </p>
      <p>For example, to map UML/OCL type occurrences to Swift 5, the following rules are used:
Type::
int |--&gt;Int32
long |--&gt;Int64
Boolean |--&gt;Bool
double |--&gt;Double
OclVoid |--&gt;Void
OclAny |--&gt;Any
Sequence(_1) |--&gt;[_1]
Set(_1) |--&gt;Set&lt;_1&gt;
No rules for occurrences of enumerations, String or entity types are needed because their
syntactic form is identical in OCL and Swift.</p>
      <p>
        The semantics of a  ℒ script is based on recursive application of string replacement in
the RHS of rules [
        <xref ref-type="bibr" rid="ref8">8</xref>
        ]. For a rule
LHS[_1,...,_n] |--&gt; RHS[_1,...,_n] &lt;when&gt; Cond[_1,...,_n]
if the LHS matches against a piece of source text LHS[t1, ..., tn], with each ti instantiating i,
then if Cond[t1, ..., tn] holds, the output text RHS[t1′, ..., tn′] is produced, where each ti′ is the
result of applying the script to ti.  ℒ provides a simple and concise notation for defining
2This library of 1107 LOC can be used independently of the UML to Swift translator. This library and OCL
libraries for other languages are available from [
        <xref ref-type="bibr" rid="ref1">1</xref>
        ].
code generators, but is relatively limited in expressiveness compared to template languages
such as Acceleo or EGL.
      </p>
      <p>The rules for translating OCL expressions are divided into five groups: (1) Basic expressions,
for literal values, variables, feature applications, etc; (2) Unary expressions, for one-argument
expression forms not(e), e→size(), etc; (3) Binary expressions, for infix binary and binary →
operators: x + y, sq→union(s), etc; (4) collection expressions Set{}, Sequence{x1, x2}, etc; (5)
Conditional and let expressions.</p>
      <p>The translation of basic expressions is direct, and includes rules such as:
null |--&gt;nil
_1.allInstances() |--&gt;_1_allInstances
For each class E, a global scope sequence var E allInstances : [E] of current E instances is
maintained in the Swift implementation.</p>
      <p>Prefix unary expressions not(e) and − e also translate directly to !(e′) and − e′ in Swift, where
e′ is the translation of e. Postfix unary expressions either translate directly to Swift, or into
Ocl.swift calls, eg.:
_1-&gt;size() |--&gt;_1.count
_1-&gt;max() |--&gt;Ocl.max(s: _1)
_1-&gt;sum() |--&gt;Ocl.sum(s: _1)</p>
      <p>Likewise, with binary expressions a direct translation is possible in some cases:
_1 mod _2 |--&gt;_1 % _2
_1-&gt;union(_2) |--&gt;_1.union(_2)&lt;when&gt; _1 Set
_1-&gt;union(_2) |--&gt;_1 + _2&lt;when&gt; _1 Sequence
_1-&gt;collect(_2 | _3) |--&gt;_1.map({_2 in _3})
where {x in e} is Swift syntax for the lambda expression  x · e.</p>
      <p>Some collection operators require specialised implementations:
_1-&gt;sortedBy(_2|_3) |--&gt;Ocl.sortedBy(s: _1, f: { _2 in _3 })
_1-&gt;select(_2 | _3) |--&gt;Ocl.select(s: _1, f: { _2 in _3 })
_1-&gt;reject(_2 | _3) |--&gt;Ocl.reject(s: _1, f: { _2 in _3 })</p>
      <p>Conditional expressions have a similar implementation in many 3GLs:
if _1 then _2 else _3 endif |--&gt;((_1) ? _2 : _3)</p>
      <p>
        To ensure that variables never hold null objects, we use the Default instance pattern, a variant
on the Singleton design pattern: for each class E, a static method defaultInstance() : E is defined,
which returns an existing instance of E if there is any E instance, otherwise it creates a new E
instance and returns it. Generated object variable declarations then have the form
var v : E = E.defaultInstance()
3. Translation of map and function types
Proposals for extending OCL with map types have been made by several researchers [
        <xref ref-type="bibr" rid="ref10 ref14 ref7">7, 14, 10</xref>
        ],
and proposals for OCL function types are given in [
        <xref ref-type="bibr" rid="ref10 ref13">10, 13</xref>
        ]. Table 1 summarises our OCL
extension map operators and their translations to Swift. These are a superset of the Eclipse
OCL Map operations [
        <xref ref-type="bibr" rid="ref2">2</xref>
        ]. The force unwrap expression e! throws an exception if e is nil.
      </p>
      <sec id="sec-2-1">
        <title>Map type/expression E</title>
        <p>Map(S, T )
m→at(x)
m[x] = y
Map{k1 ↦→ v1, ..., kn ↦→ vn}
m→size()
m1→keys()
m1→values()
m1→union(m2)
m1→intersection(m2)
m1 − m2
m→restrict(ks)
m→select(x | P)
m→collect(x | e)</p>
      </sec>
      <sec id="sec-2-2">
        <title>Semantics</title>
      </sec>
      <sec id="sec-2-3">
        <title>Finite maps from S to T</title>
        <p>m applied to x
m updated by x ↦→ y
Literal map
Number of mappings in m
Set of keys in m1
Range of m1
m1 overridden by m2
Common mappings of m1, m2
Mappings of m1 not in m2
Mappings of m with key in ks
s ↦→ t of m where t |= P
Map composition of m and e</p>
      </sec>
      <sec id="sec-2-4">
        <title>Swift 5 implementation E</title>
      </sec>
      <sec id="sec-2-5">
        <title>Dictionary&lt;S,T&gt;</title>
        <p>m[x]!
m[x] = y
[k1:v1, ..., kn:vn]
m.count
Ocl.mapKeys(m: m1)
Ocl.mapRange(m: m1)
Ocl.unionMap(m1: m1, m2: m2)
Ocl.intersectionMap(m1: m1, m2: m2)
Ocl.excludeAllMap(m1: m1, m2: m2)
Ocl.restrict(m: m, ks: ks)
Ocl.selectMap(m: m, f: { x in P })
Ocl.collectMap(m: m, f: { x in e })</p>
        <p>We extend the  ℒ code generation specification of Section 2 with type and expression
rules for maps and functions, eg.:
Map(_1,_2) |--&gt;Dictionary&lt;_1,_2&gt;
Function(_1,_2) |--&gt;(_1)-&gt;_2
_1-&gt;keys() |--&gt;Ocl.mapKeys(m: _1)
_1-&gt;values() |--&gt;Ocl.mapRange(m: _1)</p>
        <p>3Functions are immutable values, in contrast to maps.
_1 |-&gt; _2 |--&gt;_1:_2
_1-&gt;at(_2) |--&gt;_1[_2]!&lt;when&gt; _1 Map
_1-&gt;union(_2) |--&gt;Ocl.unionMap(m1: _1, m2: _2)&lt;when&gt; _1 Map
_1-&gt;intersection(_2) |--&gt;Ocl.intersectionMap(m1: _1, m2: _2)&lt;when&gt; _1 Map
_1 - _2 |--&gt;Ocl.excludeAllMap(m1: _1, m2: _2)&lt;when&gt; _1 Map
_1-&gt;restrict(_2) |--&gt;Ocl.restrict(m: _1, ks: _2)
_1-&gt;collect(_2 | _3) |--&gt;Ocl.collectMap(m: _1, f: {_2 in _3})&lt;when&gt; _1 Map</p>
        <p>The default map value is the empty map [:], the default function value of Function(S, T ) is
the function that returns the default value of T for each S element.</p>
        <p>Lambda expressions are directly implemented by closures:
lambda _1 : _2 in _3 |--&gt;{ (_1 : _2) -&gt; _3‘type in _3 }
i‘type denotes the translation of the type metafeature of the source expression bound to i.</p>
        <p>
          In the directories oclmapexamples.zip and oclfunctionexamples.zip on [
          <xref ref-type="bibr" rid="ref1">1</xref>
          ] we give examples
of specifications using maps and functions, together with the corresponding generated code in
Java, C, Swift and Python. The code generators and support libraries for these languages, and
examples of iOS apps synthesised using the Swift code generator [
          <xref ref-type="bibr" rid="ref9">9</xref>
          ] are also provided on [
          <xref ref-type="bibr" rid="ref1">1</xref>
          ].
        </p>
      </sec>
    </sec>
    <sec id="sec-3">
      <title>4. Evaluation</title>
      <p>In this section we evaluate the eficiency of map and function code implementations generated
by AgileUML. Two evaluation cases are used: (i) a word-count algorithm using maps; (ii) a
numerical optimisation procedure using functions. All Java, C and Python tests were carried
out on a Windows 10 i5-6300 dual core laptop with 2.4GHz clock frequency, 8GB RAM + 3MB
cache. For Swift we also tested execution on a similar iMac running MacOS 10 (dual core i5,
2.3GHz/8GB RAM/4MB cache). The REM IDE was used for Swift execution on Windows4.
4.1. Maps example: word counts
This example stores word counts of the words in an input sequence sq in a result map using
assignments result[x] := sq-&gt;count(x).</p>
      <p>Table 3 shows the execution times of wordCount for inputs of 1000, 10000 and 100000 words,
for the Swift, Java, Python and C implementations generated from the example using AgileUML.
All times are in seconds, computed as an average of 3 independent executions, using the same
datasets. The MacOS implementation of Swift is intermediate in performance between C and
Python.</p>
      <sec id="sec-3-1">
        <title>Java</title>
        <p>Python
Swift (MacOS)
Swift (Windows)
C
4.2. Functions example: numerical optimisation
The test example for functions uses function types and function evaluation as part of a numerical
optimisation procedure:
class SomeFunctions {
static operation secant(rn : double , rminus : double , fminus : double ,
tol : double , f : Function(double,double) ) : double
pre: true
post: fn = f(rn) and
(if fn-&gt;abs() &lt; tol then result = rn
else (
result = SomeFunctions.secant(rn</p>
        <p>fn * ( ( rn - rminus ) / ( fn - fminus ) ), rn,fn,tol,f)
}
)
endif);
The secant routine is invoked with f instantiated by lambda expressions lambda x : double in x *
x + x − 1, lambda x : double in x→pow(x) − 0.7. Table 4 shows the execution time of this
example in Java, Python, Swift and C, for 1000 function calls, 10,000 and 100,000. This case has
an approximately linear time complexity. Swift on MacOS is faster than both Python and Java,
and comparable to C.</p>
      </sec>
      <sec id="sec-3-2">
        <title>Java</title>
        <p>Python
Swift (MacOS)
Swift (Windows)
C</p>
      </sec>
    </sec>
    <sec id="sec-4">
      <title>5. Related work</title>
      <p>Three general approaches for defining mappings from UML and OCL to programming languages
are Model-to-model (M2M), Model-to-text (M2T) or Text-to-text (T2T). Table 5 compares
examples of the three approaches with regard to their size and scope. T2T solutions are substantially
more concise than M2M or M2T solutions, relative to the supported functionality (scope) of the
code generator.</p>
    </sec>
    <sec id="sec-5">
      <title>Conclusions References</title>
      <p>
        We have shown that  ℒ can be used to define a practical translation from OCL to Swift.
This translation includes support for OCL map and function extensions and regular expressions.
The translation is used to generate the business tier code of SwiftUI apps [
        <xref ref-type="bibr" rid="ref9">9</xref>
        ].
      </p>
    </sec>
  </body>
  <back>
    <ref-list>
      <ref id="ref1">
        <mixed-citation>
          [1] AgileUML repository, https://github.com/eclipse/agileuml/,
          <year>2021</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref2">
        <mixed-citation>
          [2]
          <string-name>
            <surname>Eclipse</surname>
            <given-names>OCL</given-names>
          </string-name>
          , https://projects.eclipse.org/projects/modeling.mdt.ocl,
          <year>2021</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref3">
        <mixed-citation>
          [3]
          <string-name>
            <surname>Eclipse</surname>
          </string-name>
          <article-title>UML2Java code generator</article-title>
          , https://git.eclipse.org/c/umlgen/,
          <source>accessed 18.8</source>
          .
          <year>2020</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref4">
        <mixed-citation>
          [4]
          <string-name>
            <given-names>S.</given-names>
            <surname>Greiner</surname>
          </string-name>
          ,
          <string-name>
            <given-names>T.</given-names>
            <surname>Buchmann</surname>
          </string-name>
          ,
          <string-name>
            <given-names>B.</given-names>
            <surname>Westfechtel</surname>
          </string-name>
          ,
          <article-title>Bidirectional transformations with QVT-R: a case study in round-trip engineering UML class models and Java source code</article-title>
          ,
          <year>Modelsward 2016</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref5">
        <mixed-citation>
          [5]
          <string-name>
            <given-names>F.</given-names>
            <surname>Jouault</surname>
          </string-name>
          ,
          <string-name>
            <surname>J. Bezivin,</surname>
          </string-name>
          <article-title>KM3: a DSL for metamodel specification , ATLAS team</article-title>
          ,
          <source>INRIA</source>
          ,
          <year>2006</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref6">
        <mixed-citation>
          [6]
          <string-name>
            <given-names>K.</given-names>
            <surname>Lano</surname>
          </string-name>
          ,
          <string-name>
            <given-names>S.</given-names>
            <surname>Yassipour-Tehrani</surname>
          </string-name>
          ,
          <string-name>
            <given-names>H.</given-names>
            <surname>Alfraihi</surname>
          </string-name>
          , and
          <string-name>
            <given-names>S.</given-names>
            <surname>Kolahdouz-Rahimi</surname>
          </string-name>
          ,
          <article-title>Translating from UML-RSDS OCL to ANSI C, OCL 2017</article-title>
          ,
          <article-title>STAF 2017</article-title>
          , pp.
          <fpage>317</fpage>
          -
          <lpage>330</lpage>
          .
        </mixed-citation>
      </ref>
      <ref id="ref7">
        <mixed-citation>
          [7]
          <string-name>
            <given-names>K.</given-names>
            <surname>Lano</surname>
          </string-name>
          ,
          <article-title>Map type support in OCL?</article-title>
          , https://www.eclipse.org/forums/index.php/t/1096077/,
          <year>November 2018</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref8">
        <mixed-citation>
          [8]
          <string-name>
            <given-names>K.</given-names>
            <surname>Lano</surname>
          </string-name>
          ,
          <string-name>
            <given-names>Q.</given-names>
            <surname>Xue</surname>
          </string-name>
          ,
          <string-name>
            <given-names>S.</given-names>
            <surname>Kolahdouz-Rahimi</surname>
          </string-name>
          ,
          <article-title>Agile specification of code generators for model-driven engineering</article-title>
          ,
          <source>ICSEA</source>
          <year>2020</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref9">
        <mixed-citation>
          [9]
          <string-name>
            <given-names>K.</given-names>
            <surname>Lano</surname>
          </string-name>
          et al.,
          <article-title>Synthesis of mobile applications using AgileUML</article-title>
          ,
          <string-name>
            <surname>ISEC</surname>
          </string-name>
          <year>2021</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref10">
        <mixed-citation>
          [10]
          <string-name>
            <given-names>K.</given-names>
            <surname>Lano</surname>
          </string-name>
          ,
          <string-name>
            <given-names>S.</given-names>
            <surname>Kolahdouz-Rahimi</surname>
          </string-name>
          ,
          <article-title>Extending OCL with map and function types</article-title>
          ,
          <source>FSEN</source>
          <year>2021</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref11">
        <mixed-citation>
          [11]
          <string-name>
            <surname>OMG</surname>
          </string-name>
          ,
          <source>Object Constraint Language 2.4 Specification</source>
          ,
          <year>2014</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref12">
        <mixed-citation>
          [12] TU/e, SLCOtoJava1.
          <article-title>0 code generator</article-title>
          , https://gitlab.tue.nl/SLCO,
          <year>2020</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref13">
        <mixed-citation>
          [13]
          <string-name>
            <given-names>E.</given-names>
            <surname>Willink</surname>
          </string-name>
          ,
          <source>Reflections on OCL 2 , Journal of Object Technology</source>
          , Vol.
          <volume>19</volume>
          , No.
          <volume>3</volume>
          ,
          <year>2020</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref14">
        <mixed-citation>
          [14]
          <string-name>
            <surname>E. Willink</surname>
          </string-name>
          <article-title>An OCL Map Type</article-title>
          ,
          <source>OCL '19</source>
          ,
          <year>2019</year>
          .
        </mixed-citation>
      </ref>
    </ref-list>
  </back>
</article>