Issue 15376: QVT 1.1 8.1.10 Errors in Examples (qvt-rtf) Source: Model Driven Solutions (Dr. Edward Willink, ed(at)willink.me.uk) Nature: Uncategorized Issue Severity: Summary: The second example contains "if result then return;" which has a non-boolean condition expression and a missing endif. In the first example, it is not clear that the revisit adds rather than overwrites. In the third and fourth examples it is not clear why the second pass reuses the context for the first rather than creates new objects. Resolution: 8.1.10 Errors in Examples The second example contains "if result then return;" which has a non-boolean condition expression and a missing endif. In the first example, it is not clear that the revisit adds rather than overwrites. In the third and fourth examples it is not clear why the second pass reuses the context for the first rather than creates new objects. Discussion The examples are much worse than suggested; verging on the diabolical. Revised Text: In 8.1.10 Replace The example below illustrates its usage: given a list of java classes (JClass instances) that have a packageName field indicating the name of the owning Package, the JClass2JPackage transformation creates a Java Package (JPackage) for each package name found in the list of java classes. transformation JClass2JPackage(inout javamodel:JAVA); main () { javamodel->objectsOfType(JClass)->jclass2jpackage();} mapping Class::jclass2jpackage() : JPackage () { init { result := resolveIn(jclass2jpackage,true) ->select(p|self.package=p.name)->first(); if result then return; } name := self.package; } In the example above, return is used to avoid creating more than two packages having the same name. by:JClass2JPackage.qvto modeltype JAVA uses 'http://www.omg.org/qvt/examples/javamodel'; transformation JClass2JPackage(inout javamodel : JAVA); main () { javamodel.objectsOfType(JClass)->jclass2jpackage(); } mapping JClass::jclass2jpackage() : JPackage { init { result := resolveoneIn(JClass::jclass2jpackage, p : JPackage | self.packageName = p.name); } if (name = null) { name := self.packageName; } } In the example above, the JClass::jclass2jpackage mapping is invoked for each JClass. Within the mapping, resolveoneIn, without a source expression, is used to examine all JPackage's created by the JClass::jclass2jpackage mapping. The p iterator traverses the JPackage's and the condition selects only those whose name matches the JClass's packageName. Using resolveoneIn rather than resolveIn ensures that at most one match is returned. The match is assigned to result for re-use avoiding the creation associated with a null result. A redundant re-assignment of name in the re-used JPackage is avoided by testing whether it has already been assigned. Replace The example below treats potential cyclic due to class inheritance dependencies. transformation Uml2Java(in uml:UML,out java:JAVA) main() : JAVA::Interface { uml->objectsOfType(Class)->map transformClass(); } mapping UML::transformClass() : JAVA::Interface () { name := "Ifce".concat(self.name); base := self.superClass->late resolve(JAVA::Interface); } byUML2JavaLate.qvto modeltype JAVA uses 'http://www.omg.org/qvt/examples/javamodel';modeltype UML uses 'http://www.omg.org/qvt/examples/umlmodel'; transformation Uml2Java(in uml:UML,out java:JAVA); main() { uml.objectsOfType(Class)->map transformClass(); } mapping UML::Class::transformClass() : JAVA::Interface { name := "Ifce" + self.name; base := self.superClass->late resolve(JAVA::Interface); } In the example above, the UML::Class::transformClass() mapping is invoked for each Class in the uml model. The mapping causes a corresponding JAVA::Interface to be created with name and base property initialization. The name is initialized by a simple String concatenation. The base requires the JAVA::Interface's corresponding to each self.superClass to be resolved and referenced. The resolve, with a source expression, locates the JAVA::Interface created by any mapping from the object referenced by the source expression. Application of this on a collection resolves all creations from each of the collection elements. Since it is awkward to ensure that the order of mapping execution is shallowest-superClass-first, a late resolve is used thereby deferring the assignment of the base property until all possible superClass'es have been created by all possible UML::Class::transformClass() executions. A late resolve expression is always executed in conjunction with an assignment. The assignment initially returns null, and the context that is required to execute the assignment later is stored as part of the trace state. Replace transformation Uml2Java(in uml:UML,out java:JAVA) main() : JAVA::Interface { uml->objectsOfType(Class)->map transformClass(); uml->objectsOfType(Class)->map transformClassInheritance(); } mapping UML::transformClass() : JAVA::Interface { name := "Ifce".concat(self.name); } mapping UML::transformClassInheritance() : JAVA:Interface { base := self.superClass->resolveIn(transformClass,JAVA::Interface); } In terms of execution, the ?late resolve? expression is always related to an assignment. Conceptually it returns null but in the meantime it stores all the information that is required to re-execute later the trace inspection and the assignment. byUML2JavaTwoPass.qvto modeltype JAVA uses 'http://www.omg.org/qvt/examples/javamodel';modeltype UML uses 'http://www.omg.org/qvt/examples/umlmodel'; transformation Uml2Java(in uml:UML,out java:JAVA); main() { uml.objectsOfType(Class)->map transformClass(); uml.objectsOfType(Class)->map transformClassInheritance(); } mapping UML::Class::transformClass() : JAVA::Interface { name := "Ifce" + self.name; } mapping UML::Class::transformClassInheritance() : JAVA::Interface { init { result := self.resolveoneIn(UML::Class::transformClass); } base := self.superClass->resolveIn(UML::Class::transformClass); } The main program now invokes the UML::Class::transformClass() mapping for each Class in the uml model to perform the first pass, then it invokes the UML::Class::transformClassInheritance() mapping for each Class to perform the second pass. The first mapping just creates a corresponding JAVA::Interface with a name initialized by a simple String concatenation. The second mapping relocates the JAVA::Interface created by the first mapping using an init section within which resolveoneIn, with self as a source expression, locates the result of the UML::Class::transformClass() mapping when applied to self. base is initialized by assigning the results of each of the superClass resolutions.. At the end of 8.2.1.22 ResolveExp Notation add See also the third and fourth examples of Section 8.1.10. At the end of 8.2.1.23 ResolveInExp Notation add See also the second and fourth examples of Section 8.1.10. Actions taken: July 18, 2010: received issue December 22, 2015: Resolved March 29, 2016: closed issue Discussion: Help wanted. Disposition: Deferred End of Annotations:===== ronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: ArsEALZTQkzUnw4T/2dsb2JhbACTN40qvUaFJQQ Date: Sun, 18 Jul 2010 09:10:38 +0100 From: Ed Willink User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; en-GB; rv:1.9.1.5) Gecko/20091204 Thunderbird/3.0 To: issues@omg.org Subject: QVT 1.1 8.1.10 Errors in Examples Hi The second example contains "if result then return;" which has a non-boolean condition expression and a missing endif. In the first example, it is not clear that the revisit adds rather than overwrites. In the third and fourth examples it is not clear why the second pass reuses the context for the first rather than creates new objects. Regards Ed Willink