Home » Modeling » M2T (model-to-text transformation) » [Xpand] Guards in templates (Feature request)([Xpand] Guards in templates (Feature request))
[Xpand] Guards in templates (Feature request) [message #525964] |
Thu, 08 April 2010 08:22  |
Eclipse User |
|
|
|
I'd like to propose an enhancement to xpand that makes writing modular and extensible templates a lot easier: By introducing guards for templates different output can be generated for model elements depending on their context.
Feature description:
DEFINE statements are enhanced by an optional "WHEN" clause:
«DEFINE templateName FOR element WHEN condition»
...
«ENDDEFINE»
When a template is invoked, only methods with their guard condition evaluating to true are considered. The polymorphic template evaluation remains as is.
Motivation:
Consider this template definition to generate a Java method for an UML operation:
«DEFINE operation(boolean markAsAbstract) FOR uml::Operation»
«EXPAND operationSimpleHead»
«EXPAND operationSignature(markAsAbstract)»
«IF !markAsAbstract»
«EXPAND operationBodyStart»
«EXPAND operationBody»
«ENDIF»
«EXPAND operationBodyEnd(markAsAbstract)»
«ENDDEFINE»
«DEFINE operationBody FOR uml::Operation»
«getReturnValue(getReturnResult())»
«ENDDEFINE»
...
Now imagine, that we want to define a different template "operationBody" for certain operations. If these special operations are marked with an own stereotype, we are lucky and just define a new template using polymorphism:
«DEFINE operationBody FOR myProfile::MyOperation»
...
«ENDDEFINE»
But what if the condition for using this special template is different? For example, we might want to use the special template when the operation has certain properties or the containing class has a certain stereotype. Using a guard, we can stick to the same solution pattern and define a specialised template:
«DEFINE operationBody FOR uml::Operation WHEN myProfile::MyStereotype.isInstance(this.owner)»
...
«ENDDEFINE»
Here "WHEN ..." acts as a guard and only those templates are considered for invocation for which the condition is true.
Without such a guard, the only solution I know is to alter the original template like this:
«DEFINE operationBody FOR uml::Operation»
«IF myProfile::MyStereotype.isInstance(this.owner)»
...
«ELSE»
«getReturnValue(getReturnResult())»
«ENDIF»
«ENDDEFINE»
However, this solution has serious drawbacks:
1) 3rd party templates, defined in .jar files can not be extended this way, because the original template has to be altered
2) It is not possible to define reusable "core" templates and extend these templates differently in different project contexts
3) Too many "if" statements in the template bodies make the templates hard to read
Thus, with the existing functionality, it is not possible to write extensible templates for the situations described above. However, in our project context, this is quite often the case: First, we use existing 3rd party templates (e.g. Fornax Hibernate Cartridge) we want to customize. Second, we provide our templates to other projects that themselves might want to customize them.
Providing the "guard" feature would help a lot in extending templates and in my opinion is a mandatory feature for effectivly reusing existing templates in own projects.
Best regards,
Ingo
|
|
| | | |
Re: [Xpand] Guards in templates (Feature request) [message #526006 is a reply to message #525964] |
Thu, 08 April 2010 10:14   |
Eclipse User |
|
|
|
Hi,
thanks to all for the fast responses! The key to my problem is extensibility and reuse: When somebody provides a template, he does not know about future needs to cutomize it in other projects. Let's have a look at the example again (BTW it's from the Fornax Java Basic Cartridge):
«DEFINE operation(boolean markAsAbstract) FOR uml::Operation»
«EXPAND operationSimpleHead»
«EXPAND operationSignature(markAsAbstract)»
«IF !markAsAbstract»
«EXPAND operationBodyStart»
«EXPAND operationBody»
«ENDIF»
«EXPAND operationBodyEnd(markAsAbstract)»
«ENDDEFINE»
«DEFINE operationBody FOR uml::Operation»
«getReturnValue(getReturnResult())»
«ENDDEFINE»
When I write this template, how can I make it customizable for project specific needs, without forcing the using project to alter it? With customization I mean changing a small part of its output while reusing the rest. There are some pretty good templates libraries available for XPand (e.g. the Fornax Hibernate Cartridge), but I always came to the point where I found no way to customize them without changing the original code.
The only chance I see for customization is to overwrite templates using polymorphism. However, as I explained in my original post, this is not always possible, because the condition when to use the other template may be different than selecting the template by the type of its parameters.
I know that a language like XPand must be carefully maintained to keep it simple and concise. However, I am really seeking for a solution to make existing templates better reusable (either this way or another). With the proposed enhancement, I see a good way to achieve this. Perhaps, the first goal should be to get a common understanding of the current limitations in writing reusable templates. If it is still unclear to you, where the core of my problem is, please let me know and I try to make another example.
@Marius: Yes, during runtime there might be an unambiguity which template to call. The behaviour here has to be carefully chosen. Maybe it is sufficient to require that only one guard may be true at any time and to throw an error, if this is not the case. In XSLT, which has a similar mechanism, a template can have a priority and the highest priorized applicable template is chosen.
Ingo
|
|
| |
Re: [Xpand] Guards in templates (Feature request) [message #526179 is a reply to message #526008] |
Fri, 09 April 2010 03:14   |
Eclipse User |
|
|
|
Hi Christian,
yes, with AOP I can do some customization, but this has some limitations.
The customization from my original posting could be realized with AOP like this:
«AROUND operationBody() FOR uml::Operation»
«IF myProfile::MyStereotype.isInstance(this.owner)»
...
«ELSE»
«targetDef.proceed()»
«ENDIF»
«ENDAROUND»
However, this definition can itself not be overwritten. Let's assume we have a template library T, defining basic templates for java fragments, such as classes, methods etc., including my example templates "operation" and "operationBody". Now imagine two other libraries E1 and E2, reusing the templates of T, but wanting to alter "operationBody" when the containing class has a certain stereotype. With my proposed enhancement, this would look like this:
Template in E1:
«DEFINE operationBody FOR uml::Operation WHEN E1::E1Stereotype.isInstance(this.owner)»
...
«ENDDEFINE»
Template in E2:
«DEFINE operationBody FOR uml::Operation WHEN E2::E2Stereotype.isInstance(this.owner)»
...
«ENDDEFINE»
With AOP this is not possible. The same is true, when E1 extends T and then E1 itself is reused and extended by E2 (this is the case in my project).
Even if AOP is applicable, I think specialising a template with a WHEN-clause is simpler to use than AOP. For example, for using AOP the generation workflow has to be altered. Also, the WHEN-clause clearly defines when to apply the template, while using AOP you have to use an IF clause in the template body (or even an IF cascade if you have multiple cases).
Best regards,
Ingo
|
|
|
Re: [Xpand] Guards in templates (Feature request) [message #526213 is a reply to message #525964] |
Fri, 09 April 2010 05:15  |
Eclipse User |
|
|
|
Hi,
I just realized that my proposed enhancement is not working as expected because of a false assumption: I thought that the polymorphic template invocation works across multiple template files. However, it seems that each template file has its own namespace, so it is impossible to write a specialised version of a template in another template file. This makes it impossible to customize a template library without AOP. Bad luck for me, because as i pointed out earlier, I think AOP has some disadvantages and I would like to find a more elegant solution.
Ingo
|
|
|
Goto Forum:
Current Time: Thu Jul 17 21:59:09 EDT 2025
Powered by FUDForum. Page generated in 0.03088 seconds
|