| <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> | |
| <html> | |
| <head> | |
| <title>ATL Basic Examples and Patterns - The Side effect example</title> | |
| <meta http-equiv="Content-Type" content="text/html; charset=windows-1252" /> | |
| <link rel="stylesheet" type="text/css" href="../layout.css" media="screen" /> | |
| <link rel="stylesheet" type="text/css" href="../article.css" media="screen" /> | |
| </head> | |
| <body> | |
| <h1>The side effect example</h1> | |
| <div class="summary"> | |
| <h2>Summary</h2> | |
| <p align="justify"> | |
| This case deals with the way to handle side effects induced while transforming an element. We will start from an imperative algorithm to create a transformation between two | |
| metamodels. This algorithm will introduce a side effect problem. After several iteration a solution will be provided following ATL philosophy. | |
| </p> | |
| <p align="justify"> | |
| In this example, we discover how: to use ATL imperative parts for dealing with complex situation, and | |
| to use a chain of ATL transformations to divide transformation complexity and to avoid imperative parts. | |
| </p> | |
| <div class="author">By Cyril Faure (CS) and Freddy Allilaire (INRIA)</div> | |
| <div class="copyright">Copyright © 2007-2008 CS and INRIA.</div> | |
| <div class="date">January, 2008</div> | |
| </div> | |
| <div class="content"> | |
| <h2>Introduction</h2> | |
| <p align="justify"> | |
| This case deals with the way to handle side effects induced while transforming an element. We will start from an imperative algorithm to create a transformation between two | |
| metamodels. This algorithm will introduce a side effect problem. After several iteration we will provide a solution following ATL philosophy. | |
| </p> | |
| <h2>The Metamodels</h2> | |
| <p align="center"> | |
| <img src="img/TypeA.PNG" /> | |
| <br /><br /> | |
| <b>Metamodel A</b> | |
| </p> | |
| <p align="justify"> | |
| The metamodel <b>A</b> is composed of two concepts which represent a simple list of named elements. Different <i>ElementA</i> can have the same name. | |
| </p> | |
| <p align="center"> | |
| <img src="img/TypeB.PNG" /> | |
| <br /><br /> | |
| <b>Metamodel B</b> | |
| </p> | |
| <p align="justify"> | |
| The metamodel <b>B</b> defines a slightly different concept with a third concept called <i>DefinitionB</i>. In this metamodel, a <i>RootB</i> element has a set of <i>DefinitionB</i> | |
| whose role is to gather and to factorize all <i>ElementB</i> name. All <i>DefinitionB</i> elements (in the context of the same <i>RootB</i> element) must have different name | |
| attribute value. | |
| </p> | |
| <h2>Goal of the transformation</h2> | |
| <p align="justify"> | |
| The goal of this example is to transform a <i>RootA</i> element into a <i>RootB</i> one and an <i>ElementA</i> into an <i>ElementB</i> one. Created <i>ElementB</i> will not contain | |
| the name from the <i>ElementA</i>. The name will be used to create a <i>DefinitionB</i> element with the requirement that each <i>DefinitionB</i> (i.e. name value) is unique. | |
| </p> | |
| <p align="justify"> | |
| The figure below illustrates transformation goal with an example: | |
| </p> | |
| <p align="center"> | |
| <img src="img/SideEffect_bigPicture.PNG" /> | |
| <br /><br /> | |
| <b>Transformation Big Picture</b> | |
| </p> | |
| <h2>A first implementation</h2> | |
| <p align="justify"> | |
| In this example, we will start with the "point of view" of an "imperative language developer" to create our transformation from metamodel A to metamodel B. | |
| Here is an algorithm we can propose in "imperative way": | |
| </p> | |
| <table STYLE="border : 1px dotted #AAAAAA;" width="100%" cellspacing="0" cellpadding="20"> | |
| <td> | |
| <code> | |
| <i>RootA</i> element is transformed into <i>RootB</i> and for each <i>ElementA</i>, | |
| <ul> | |
| <li>we create an <i>ElementB</i></li> | |
| <li>we store b in the <i>RootB.elms</i> containment relation</li> | |
| <li>we make a traversal of <i>RootB.defs</i>. For each <i>d : DefinitionB</i>, | |
| <ul> | |
| <li>if <i>a.name = d.name</i>, then we put the <i>d</i> reference as <i>b</i> 's definition : <i>b.def <- d</i> and end the traversal</li> | |
| <li>else, we carry on the traversal to the next element</li> | |
| </ul> | |
| </li> | |
| <li>if no definition <i>d</i> has been found such as <i>a.name = d.name</i>: | |
| <ul> | |
| <li>we create a <i>newD : DefinitionB</i> where <i>newD.name = a.name</i></li> | |
| <li>we put the <i>newD</i> reference as <i>b</i> 's definition : <i>b.def <- newD</i></li> | |
| </ul> | |
| </li> | |
| </ul> | |
| </code> | |
| </td> | |
| </table> | |
| <p align="justify"> | |
| As one can see, for each <i>ElementB</i> created whose definition is not already available, the algorithm creates it on-the-fly, inducing a side effect. | |
| </p> | |
| <p align="justify"> | |
| The following implementation succeeded to reproduce the algorithm described above by writing a single rule transforming the source root object into the target root | |
| object. Note this rule may be dangerous as it assumes the ATL engine executes the bindings in the order they are written in the code. | |
| </p> | |
| <p align="justify"> | |
| <b>Remark:</b> The target model is browsed in this transformation, this is <b>strongly discouraged in ATL</b>. | |
| </p> | |
| <table STYLE="border : 1px dotted #AAAAAA;" width="100%" cellspacing="0" cellpadding="20"> | |
| <td> | |
| <code> | |
| <pre> | |
| <font class="ATL_Keyword">module</font> TypeA2TypeB; | |
| <font class="ATL_Keyword">create</font> b : TypeB <font class="ATL_Keyword">from</font> a : TypeA; | |
| <font class="ATL_Comment">-- This helper retrieves all names and removes all duplicates</font> | |
| <font class="ATL_Keyword">helper context</font> TypeA!RootA <font class="ATL_Keyword">def</font> : getDefNameSet() : <font class="ATL_OCLType">Set</font>(<font class="ATL_OCLType">String</font>) = | |
| self.elms->collect(e|e.name).asSet(); | |
| <font class="ATL_Keyword">rule</font> RootA2RootB { | |
| <font class="ATL_Keyword">from</font> | |
| rtA : TypeA!RootA | |
| <font class="ATL_Keyword">to</font> | |
| <font class="ATL_Comment">-- this rule is dangerous as we suppose the ATL engine executes...</font> | |
| rtB : TypeB!RootB ( | |
| <font class="ATL_Comment">-- this line before...</font> | |
| defs <- defBLst, | |
| <font class="ATL_Comment">-- this one.</font> | |
| elms <- elmBLst | |
| ), | |
| defBLst : <font class="ATL_Keyword">distinct</font> TypeB!DefinitionB <font class="ATL_Keyword">foreach</font>(defName <font class="ATL_Keyword">in</font> rtA.getDefNameSet ())( | |
| name <- defName | |
| ), | |
| elmBLst : <font class="ATL_Keyword">distinct</font> TypeB!ElementB <font class="ATL_Keyword">foreach</font> (elmA <font class="ATL_Keyword">in</font> rtA.elms) ( | |
| <font class="ATL_Comment">-- here the target model is browsed</font> | |
| definition <- rtB.defs->select (d | d.name = elmA.name )->first() | |
| ) | |
| } | |
| </pre> | |
| </code> | |
| </td> | |
| </table> | |
| <p align="justify"> | |
| As one can see, the described algorithm contains a side effect where the <i>DefinitionB</i> elements creation are made on-the-fly. This implementation makes | |
| a dangerous assertion as the ATL engine does not ensure the bindings execution order (this is a consequence of target model browsing). | |
| </p> | |
| <h2>How to follow the ATL philosophy</h2> | |
| <p align="justify"> | |
| In respect of the ATL philosophy, we would like to have a rule where: | |
| </p> | |
| <table STYLE="border : 1px dotted #AAAAAA;" width="100%" cellspacing="0" cellpadding="20"> | |
| <td> | |
| <code> | |
| <pre> | |
| <font class="ATL_Keyword">rule</font> ElmA2ElmB { | |
| <font class="ATL_Keyword">from</font> | |
| elmA : A!ElementA | |
| <font class="ATL_Keyword">to</font> | |
| elmB : B!ElementB( | |
| ) | |
| } | |
| </pre> | |
| </code> | |
| </td> | |
| </table> | |
| <p align="justify"> | |
| However if we plan to use such a rule, how can we set the <i>def</i> reference and reproduce the associated side effect (on-the-fly <i>DefinitionB</i> creation) in a more | |
| functional way? | |
| </p> | |
| <p align="justify"> | |
| The following ATL code proposed an other solution to reach transformation goal: | |
| </p> | |
| <table STYLE="border : 1px dotted #AAAAAA;" width="100%" cellspacing="0" cellpadding="20"> | |
| <td> | |
| <code> | |
| <pre> | |
| <font class="ATL_Keyword">module</font> TypeA2TypeB; | |
| <font class="ATL_Keyword">create</font> b : TypeB <font class="ATL_Keyword">from</font> a : TypeA; | |
| <font class="ATL_Keyword">rule</font> RootA2RootB { | |
| <font class="ATL_Keyword">from</font> | |
| rtA : TypeA!RootA | |
| <font class="ATL_Keyword">to</font> | |
| rtB : TypeB!RootB ( | |
| defs <- rtA.elms->iterate(e; res : <font class="ATL_OCLType">Set</font>(TypeA!ElementA) = <font class="ATL_OCLType">Set</font> {} | | |
| <font class="ATL_Keyword">if</font> (res->collect(f | f.name)->includes(e.name)) <font class="ATL_Keyword">then</font> | |
| res | |
| <font class="ATL_Keyword">else</font> | |
| res->including(e) | |
| <font class="ATL_Keyword">endif</font> | |
| )<font class="ATL_Comment">-- here we keep only one element of each name value</font> | |
| ->collect(e | thisModule.Definition(e)), | |
| <font class="ATL_Comment">-- then we create a DefinitionB from each selected element</font> | |
| elms <- rtA.elms | |
| ) | |
| } | |
| <font class="ATL_Keyword">lazy rule</font> Definition { | |
| <font class="ATL_Keyword">from</font> | |
| s : TypeA!ElementA | |
| <font class="ATL_Keyword">to</font> | |
| t : TypeB!DefinitionB( | |
| name <- s.name | |
| ) | |
| } | |
| <font class="ATL_Keyword">helper def</font>: nameToAssignHistory : <font class="ATL_OCLType">Sequence</font>(<font class="ATL_OCLType">TupleType</font>(e : TypeB!ElementB, s : <font class="ATL_OCLType">String</font>)) = | |
| <font class="ATL_OCLType">Sequence</font> {}; | |
| <font class="ATL_Keyword">rule</font> NameToAssign (e : TypeB!ElementB, s : <font class="ATL_OCLType">String</font>) { | |
| <font class="ATL_Keyword">do</font> { | |
| thisModule.nameToAssignHistory <- thisModule.nameToAssignHistory->append(<font class="ATL_OCLType">Tuple</font> {e = e, s = s}); | |
| } | |
| } | |
| <font class="ATL_Keyword">rule</font> Element { | |
| <font class="ATL_Keyword">from</font> | |
| s : TypeA!ElementA | |
| <font class="ATL_Keyword">to</font> | |
| t : TypeB!ElementB( | |
| ) | |
| <font class="ATL_Keyword">do</font> { | |
| <font class="ATL_Comment">-- The corresponding name for the current ElementB is added in the map.</font> | |
| <font class="ATL_Comment">-- This map will be used at the end of the transformation to create a link between ElementB and DefinitionB</font> | |
| thisModule.NameToAssign(t, s.name); | |
| } | |
| } | |
| <font class="ATL_Comment">-- execute delayed actions</font> | |
| <font class="ATL_Keyword">endpoint rule</font> EndRule() { | |
| <font class="ATL_Keyword">do</font> { | |
| <font class="ATL_Keyword">for</font>(dta <font class="ATL_Keyword">in</font> thisModule.nameToAssignHistory) { | |
| <font class="ATL_Comment">-- We create a link between an ElementB and the corresponding DefinitionB</font> | |
| dta.e.definition <- TypeB!DefinitionB.allInstancesFrom(<font class="ATL_Enum">'b'</font>)->any(e | e.name = dta.s); | |
| } | |
| } | |
| } | |
| </pre> | |
| </code> | |
| </td> | |
| </table> | |
| <p align="justify"> | |
| This ATL transformation also required target models browsing (even this is done in the endpoint). This solution may be consider better than the first one. But it does not | |
| give satisfaction. As you can see, it uses some imperative constructs that made it more difficult to understand and to maintain. As it seems not possible to solve | |
| this by using only one transformation without imperative code, we should consider to solve it by using a chain of transformations. This will allow us to | |
| solve each problem in a different transformation. | |
| </p> | |
| <p align="justify"> | |
| The general overview of our approach is presented in the following figure: | |
| </p> | |
| <p align="center"> | |
| <img src="img/SideEffect_lastVersionScenario.png" /> | |
| </p> | |
| <h3>First step: A to Partial_B</h3> | |
| <p align="justify"> | |
| In the first step, we create a partial model B containing the list of <i>DefinitionB</i> elements. | |
| </p> | |
| <table STYLE="border : 1px dotted #AAAAAA;" width="100%" cellspacing="0" cellpadding="20"> | |
| <td> | |
| <code> | |
| <pre> | |
| <font class="ATL_Keyword">module</font> TypeA2TypeB; | |
| <font class="ATL_Keyword">create</font> b : TypeB <font class="ATL_Keyword">from</font> a : TypeA; | |
| <font class="ATL_Keyword">rule</font> RootA2RootB { | |
| <font class="ATL_Keyword">from</font> | |
| rtA : TypeA!RootA | |
| <font class="ATL_Keyword">to</font> | |
| rtB : TypeB!RootB ( | |
| defs <- rtA.elms->iterate(e; res : <font class="ATL_OCLType">Set</font>(TypeA!ElementA) = <font class="ATL_OCLType">Set</font> {} | | |
| <font class="ATL_Keyword">if</font> (res->collect(f | f.name)->includes(e.name)) <font class="ATL_Keyword">then</font> | |
| res | |
| <font class="ATL_Keyword">else</font> | |
| res->including(e) | |
| <font class="ATL_Keyword">endif</font> | |
| )->collect(e | thisModule.Definition(e)) | |
| ) | |
| } | |
| <font class="ATL_Keyword">lazy rule</font> Definition { | |
| <font class="ATL_Keyword">from</font> | |
| s : TypeA!ElementA | |
| <font class="ATL_Keyword">to</font> | |
| t : TypeB!DefinitionB( | |
| name <- s.name | |
| ) | |
| } | |
| </pre> | |
| </code> | |
| </td> | |
| </table> | |
| <h3>Second step: A and Partial_B to B</h3> | |
| <p align="justify"> | |
| In the second step, we can easily solve the problem by using in input parameter the output model created by the first step transformation. | |
| </p> | |
| <table STYLE="border : 1px dotted #AAAAAA;" width="100%" cellspacing="0" cellpadding="20"> | |
| <td> | |
| <code> | |
| <pre> | |
| <font class="ATL_Keyword">module</font> TypeA2TypeB; | |
| <font class="ATL_Keyword">create</font> b : TypeB <font class="ATL_Keyword">from</font> a : TypeA, bIn : TypeB; | |
| <font class="ATL_Keyword">rule</font> RootA2RootB { | |
| <font class="ATL_Keyword">from</font> | |
| rtA : TypeA!RootA, rtBIN : TypeB!RootB | |
| <font class="ATL_Keyword">to</font> | |
| rtB : TypeB!RootB ( | |
| defs <- rtBIN.defs, | |
| elms <- rtA.elms | |
| ) | |
| } | |
| <font class="ATL_Keyword">rule</font> Definition { | |
| <font class="ATL_Keyword">from</font> | |
| s : TypeB!DefinitionB | |
| <font class="ATL_Keyword">to</font> | |
| t : TypeB!DefinitionB( | |
| name <- s.name | |
| ) | |
| } | |
| <font class="ATL_Keyword">rule</font> Element { | |
| <font class="ATL_Keyword">from</font> | |
| s : TypeA!ElementA | |
| <font class="ATL_Keyword">to</font> | |
| t : TypeB!ElementB( | |
| definition <- TypeB!DefinitionB.allInstancesFrom(<font class="ATL_Enum">'bIn'</font>)->any(e | e.name = s.name) | |
| ) | |
| } | |
| </pre> | |
| </code> | |
| </td> | |
| </table> | |
| <h2>Conclusion</h2> | |
| <p align="justify"> | |
| What we have learnt with this example: | |
| <ul> | |
| <li>Using ATL imperative parts for dealing with complex situation.</li> | |
| <li>Using a chain of ATL transformations to divide transformation complexity and to avoid imperative parts.</li> | |
| </ul> | |
| </p> | |
| <h2>Download</h2> | |
| <table width="100%"> | |
| <COLGROUP> | |
| <COL width="10%"> | |
| <COL width="25%"> | |
| <COL width="65%"> | |
| </COLGROUP> | |
| <tr> | |
| <td align="right"> | |
| <a href="https://www.eclipse.org/atl/atlTransformations/ManyToMore/ManyToMore.zip"> | |
| <img style="vertical-align:text-top;" src="/resources/images/code.png"/> | |
| </a> | |
| </td> | |
| <td align="left"> | |
| <a href="https://www.eclipse.org/atl/atlTransformations/SideEffect/SideEffect.zip"><h3>SideEffect</h3></a> | |
| </td> | |
| <td align="left">Source code for the scenario SideEffect.</td> | |
| </tr> | |
| </table> | |
| <h2><a name="acknowledgement"></a>Acknowledgement</h2> | |
| The present work is being supported by the <a href="https://www.usine-logicielle.org">Usine Logicielle project of the System@tic Paris Region Cluster</a>. | |
| </div> | |
| </body> | |
| </html> |