Thursday, May 27, 2010

Acceleo : OCL made simple

It was recently asked on a mailing list how one would order the elements they iterate over in an Acceleo for loop. The elements were UML ControlFlows as in :


- Package
|-- Activity
   |-- ControlFlow1
   |-- ControlFlow2
   |-- ControlFlow3


The first answer that came to mind, using standard OCL, was :

[for (cf:ControlFlow |c.ownedElement->select(a|a.oclIsKindOf(ControlFlow))->sortedBy(e: Element | e.oclAsType(ControlFlow).name))]
...
[/for]


Pretty verbose ... If we instead make use of the implicit iterators Acceleo offers, the expression can be simplified to

[for (c.ownedElement->select(oclIsKindOf(ControlFlow))->sortedBy(oclAsType(ControlFlow).name))]
...
[/for]


But this still sports the redundancy of filtering from a list only the elements of a given type (select) and then casting the elements to ... that very same type (oclAsType). This is due to OCL not allowing Acceleo to infer the return type of the select operation. Starting from Acceleo 3.0, this expression can also be written

[for (c.ownedElement->filter(ControlFlow)->sortedBy(name))]
...
[/for]


Now that's better!