Issue 18324: No trace data for disjuncting mapping (qvt-rtf) Source: (, ) Nature: Clarification Severity: Significant Summary: Trace data creation is specified to happen "at the end of the initialization section". For disjuncting mappings, the initialization section is never executed, which prevents any trace data from being stored. As a consequence, no resolution via resolve-in-expressions is possible on the disjuncting mapping, due to the missing trace record. This is problematic, since disjunction should be transparent from a resolver's point of view, i.e. it should not make a difference for resolution whether a mapping disjuncts or not. Hence, some clarification is required whether trace records are deliberately avoided for disjuncting mappings (for whatever reason), or whether trace data must be created in another place than the init section in case of a disjuncting mapping. Resolution: No trace data for disjuncting mapping Trace data creation is specified to happen "at the end of the initialization section". For disjuncting mappings, the initialization section is never executed, which prevents any trace data from being stored. As a consequence, no resolution via resolve-in-expressions is possible on the disjuncting mapping, due to the missing trace record. This is problematic, since disjunction should be transparent from a resolver's point of view, i.e. it should not make a difference for resolution whether a mapping disjuncts or not. Hence, some clarification is required whether trace records are deliberately avoided for disjuncting mappings (for whatever reason), or whether trace data must be created in another place than the init section in case of a disjuncting mapping. Discussion It seems the 8.1.x section on Tracing never got written. Time for a thorough review and clarification. Trace lookups by source objects treat context and all in/inout parameters as source objects. Trace lookups by target objects treat all out/inout and result parameters as target objects. Trace lookups by mapping allow either disjuncting mapping or candidate mapping to be used as the mapping selection. If re-execution is to be completely suppressed and fully re-use a previous execution, the output trace should be the final outputs, but the existing text is clear that it is the preliminary outputs at the end of the initialization section. The earlier trace gives a slightly different semantics that requires the population section to modify the created object after it is traced and allows the population section to use the trace. This is different but fine when explained clearly. References to 8.1.12 refer to the new text from the [1]QVT13-99 resolution. ---------------------------------------------------------------------------------------- [1] http://issues.omg.org/browse/QVT13-99 Revised Text: In 8.1.4 change { init { ? } population { ? } end { ? } } to { // inhibition section - see Section 8.1.10.2init { ? } // instantiation section - see Section 8.1.10.2population { ? } end { ? } } In 8.1.4 replace Between the initialization and the population sections, there is an implicit section, named the instantiation section, which creates all output parameters that have a null value at the end of the initialization section. This means that, in order to return an existing object rather than creating a new one, one simply needs to assign the result parameter within the initialization section. by Before the init, there is an implicit section, named the inhibition section, which suppresses redundant re-execution of a mapping. Following the init and before the population sections, there is an implicit section, named the instantiation section, which creates all output parameters that have a null value at the end of the initialization section. The null value tests mean that, in order to return an existing object rather than creating a new one, one simply needs to assign the result parameter within the init section.The instantiation section also creates the trace record of the execution. In 8.1 before 8.1.10 Add a new section 8.1.x Tracing and Resolving Execution of a mapping establishes a trace record to maintain the relationship between its context object and the result object or objects. This relationship can be queried using one of the eight resolve expressions. 8.1.x.1 Trace Records Execution of a transformation builds the overall trace-data which comprises a sequence of trace-records; one for each mapping execution in execution order. This includes every mapping executed by, accessed or extended, transformations or libraries, but not those by transformation invocations. Each trace-record comprises: *context-parameter - the context parameter object *in-parameters - the in and inout parameter objects or values *invoked-mapping - the invoked mapping operation *executed-mapping - the executed mapping operation *out-parameters - the out parameter objects or values *result-parameters - the result parameter object or objects The invoked-mapping and executed-mapping operations may differ when a disjuncting mapping is executed. The invoked-mapping is the disjuncting mapping. The executed-mapping is the successfully selected candidate mapping or null. inout parameters are traced once as in-parameters; they cannot change during production of the trace-record. The trace-record is created during the instantiation section of the selected candidate mapping, which is after the initialization section and before the population section. A trace-record is created by every mapping execution, unless predicates or initialization section fail. A trace-record is created or re-used by every mapping invocation, unless predicates or initialization section fail. In the case of a standard mode execution for which no candidate mapping is selected, the executed-mapping, out-parameters and result-parameters are null. The following example mapping declarations mapping X::disjunctingMapping(in p1:P1, inout p2:P2, out p3:P3) : r1:R1, r2:R2 disjuncts mappingName, ... {} mapping X::mappingName(in p1:P1, inout p2:P2, out p3:P3) : r1:R1, r2:R2 ..{...} may be invoked as var t := anX.map disjunctingMapping(aP1, aP2, aP3); var anR1 := t.r1; var anR2 := t.r2; to create the following trace-record. (Hyphens are used in names that are helpful for exposition, but which are not accessible to program code.) object Trace-Record { context-parameter := anX; in-parameters := Sequence{aP1, aP2}; invoked-mapping := X::disjunctingMapping; executed-mapping := X::mappingName; out-parameters := Sequence{aP3}; result-parameters := Sequence{anR1, anR2}; } The trace-record traces the relationship between mapping inputs and outputs; between the inputs {anX, aP1, aP2} and the outputs {aP3, anR1, anR2}. Note that there is no trace for object construction in helpers or for nested object construction in mappings. If a trace of all objects is needed, a mapping must be used to create each object as a mapping output. 8.1.x.2 The inhibition and instantiation sections The auto-generated inhibition and instantiation sections surround the initialization section of a mapping, whose general structure is: mapping X::mappingName(in p1:P1, inout p2:P2, out p3:P3) : r1:R1, r2:R2 when { ? } where { ? } { // inhibition sectionvar trace-records := trace-data ->select(executed-mapping=X::mappingName) ->select(context-parameter=self) ->select(in-parameters->at(1)=p1) ->select(in-parameters->at(2)=p2); if (trace-records->notEmpty()) { var trace-record := trace-records->at(1); p3 := trace-record.out-parameters->at(1); r1 := trace-record.result-parameters->at(1); r2 := trace-record.result-parameters->at(2); return; }; init { ? } // instantiation sectionif (p3 == null) p3 := object P3{}; if (r1 == null) r1 := object R1{}; if (r2 == null) r2 := object R2{}; trace-data += object Trace-Record{ context-parameter:=self, in-parameters:=Sequence{p1, p2}, invoked-mapping:=X::dislunctingName, executed-mapping:=X::mappingName, out-parameters:=Sequence{p3}, result-parameters:=Sequence{r1,r2} }; population { ? } end { ? } } In the inhibition section, the trace-data is consulted to locate all trace-records whose executed-mapping, context-parameter and in-parameters match the new candidate mapping invocation. If a match is found, the previous out-parameters and result-parameters are used as the mapping return values and the mapping re-execution is suppressed. Then the initialization section provides an opportunity for the default null values of outputs to be replaced by something more useful. If the null values are unchanged, the instantiation section constructs an object for each object. inout parameters may not be changed during the initialization section. Finally the execution of the mapping is recorded by adding a trace-record to the trace-data. A candidate mapping execution is suppressed to avoid creating a trace-record whose context-parameter, in-parameters, invoked-mapping and executed-mapping fields duplicate another trace-record already in the trace-data. When comparing trace-record fields, Class instances are compared as objects without regard for their content, and DataType values are compared by deep value equality. Traced object instances may therefore be modified between mapping executions without inhibiting detection of re-execution since only the object references are traced. However any modification of a traced DataType value such as a List inhibits detection of a re-execution since the entire value is traced. When a re-execution attempt is detected, the re-execution is suppressed without any additional trace-record being created. Note that traced Class instances are mutable and so the re-used value may have changed in the interim. 8.1.x.3 resolve() - Resolution of target objects by Type The trace data may be queried to identify all target objects using the resolve operation without a context object or argument. resolve() The query may be restricted to identifying all target objects conforming to a given type by adding a type argument. resolve(Table) The returned target objects may be restricted to those mapped from a particular source object by supplying the source object as the context object. source.resolve() Additionally, or alternatively, the returned target objects may be restricted by an OCL condition. source.resolve(t : Table | t.name.startsWith('_')) These queries return a sequence of target objects in mapping invocation order. An equivalent OCL-like query for SOURCE.resolve(T : TYPE | CONDITION) is let selectedRecords = trace-data->select(in-parameters->including(context-parameter)->includes(SOURCE)) in let selectedTargets = selectedRecords->collect(out-parameters->union(result-parameters)) in selectedTargets->selectByKind(TYPE)->select(T | CONDITION) 8.1.x.4 resolveIn() - Resolution of target objects by Mapping The trace data may be queried to identify all target objects produced by a given invoked disjuncting mapping or executed candidate mapping using the resolveIn expression. resolveIn(Class2Table) The returned target objects may be restricted to those mapped from a particular source object by supplying the source object as the context object. source.resolveIn(Class2Table) Additionally, or alternatively, the returned target objects may be restricted by an OCL condition. source.resolveIn(Class2Table, t : Table | t.name.startsWith('_')) These queries return a sequence of target objects in mapping invocation order. An equivalent OCL-like query for SOURCE.resolveIn(MAPPING, T : TYPE | CONDITION) is let selectedRecords1 = trace-data->select(in-parameters->including(context-parameter)->includes(SOURCE)) in let selectedRecords2 = selectedRecords1->select((invoked-mapping = MAPPING) or (executed-mapping = MAPPING)) in let selectedTargets = selectedRecords2->collect(out-parameters->union(result-parameters)) in selectedTargets->selectByKind(TYPE)->select(T | CONDITION) 8.1.x.5 invresolve() - Resolution of source objects by Type or Mapping The corresponding inverse queries are available using the invresolve or invresolveIn expressions. These identify source objects mapped to a given type or by a given mapping. invresolve() // all sources invresolve(Class) // all sources of kind Class target.invresolve() // all sources mapped to target target.invresolve(c : Class | c.name.startsWith('_')) invresolveIn(Class2Table) // all sources for Class2Table mappings target.invresolveIn(Class2Table) // all sources mapped to target by a Class2Table mapping target.invresolveIn(Class2Table, c : Class | c.name.startsWith('_')) 8.1.x.6 resolveone() - Resolution of a single source or target object by Type or Mapping The four resolveone variants of the four resolve expressions modify the return to suit the common case where only a single object is expected. The return is therefore the first resolved object or null. resolveone() // the first target resolveone(Table) // the first target of kind Table source.resolveone() // the first target mapped from source source.resolveone(t : Table | t.name.startsWith('_')) resolveoneIn(Class2Table) // the first target of a Class2Table mapping source.resolveoneIn(Class2Table) // the first target mapped from source by a Class2Table mapping source.resolveoneIn(Class2Table, t : Table | t.name.startsWith('_')) invresolveone() // the first source invresolveone(Class) // the first source of kind Class target.invresolveone() // the first source mapped to target target.invresolveone(c : Class | c.name.startsWith('_')) invresolveoneIn(Class2Table) // the first source for a Class2Table mapping target.invresolveoneIn(Class2Table) // the first source mapped to target by a Class2Table mapping target.invresolveoneIn(Class2Table, c : Class | c.name.startsWith('_')) 8.1.x.7 Late resolution The resolve expressions query the prevailing state of the trace data. resolve cannot of course return results from mappings that have yet to execute and so careful programming of mapping invocations may be required to ensure that required results are available when needed. Alternatively a late keyword may prefix resolve when the resolution occurs within an assignment. This defers the execution of the assignment and the partial computation involving late resolve's until all mapping executions have completed. The deferred assignment cannot return the future value; it therefore returns a null value. More precisely, mappings execute, assignment right hand sides involving late resolutions are computed, then finally deferred assignments are made. The ordering in which late resolutions occur does not matter, since each late resolution can influence only its own deferred assignment. myprop := mylist->late resolve(Table); // shorthand for mylist->xcollect(late resolve(Table)) This last example also demonstrates that an implicit imperative xcollect of resolutions may be performed, in this case requiring the collection to be performed after all mappings have executed. 8.1.x.8 Persisted Trace Data The trace data may be persisted and reloaded to support a re-execution. However the trace record does not trace configuration data, transformation properties or intermediate data, and does not involve a deep clone of every traced object. It is therefore not possible to use a persisted form of the trace data to support incremental re-execution of an arbitrary QVTo transformation since the required object state may not be present in persisted trace. A well-behaved transformation that avoids dependence on mutable object properties or other untraced facilities may be re-executable. In 8.2.1.15 Correct A mapping operation is an operation implementing a mapping between one or more source model elements- intoand one or more target model elements. In 8.2.1.15 Replace The when clause acts either as a pre-condition or as a guard, depending on the invocation mode of the mapping operation. by The when clause acts either as a pre-condition when invoked with strict semantics, or as a guard, when invoked using standard semantics. In 8.2.1.15 Replace The initialization section is used for computation prior to the effective instantiation of the outputs. The population section is used to populate the outputs and the finalization section is used to define termination computations that take place before exiting the body. by The init (initialization) section is used for computation prior to the effective instantiation of the outputs. The population section is used to populate the outputs and the end (finalization) section is used to define termination computations that take place before exiting the body. In 8.2.1.15 Replace There are three reuse and composition facilities associated to mapping operations: by A mapping operation may be explicitly defined as a disjunction of candidate mapping operations. Every mapping operation is also an implicit disjunction of all mappings that are overloads as a consequence of matching name and argument count. Execution of a disjunction involves selecting the first candidate mapping whose when clause and other predicates are satisfied and then invoking it. This is described in Section 8.1.12. The empty body of the disjuncting mapping is not executed. Additionally, there are two extension mechanisms associated to mapping operations: In 8.2.1.15 Replace 3. A mapping operation may be defined as a disjunction of other mapping operations. This means selecting, among the set of disjuncted mappings, the first that satisfies the when clause and then invoking it. The execution semantics subsection below provides the details of these reuse facilities. by The execution semantics subsection below provides the details of these mapping extension mechanisms. In 8.2.1.15 Constraints add The body of a disjuncting mapping must be empty. disjunct->notEmpty() implies body = null In 8.2.1.15 Replace We first define the semantic of the execution of a mapping operation in absence of any reuse facility (inheritance, merge, and disjunction), then we describe the effect of using these facilities. by We firstly define the semantic of the execution of a mapping operation in the absence of any inheritance or merge reuse facility. In 8.2.1.21 Replace Indicates the mode of the mapping invocation. by Indicates whether the mapping invocation mode is strict or standard. In 8.2.1.21 Replace In strict mode the when clause is evaluated as a pre-condition. In contrast, when the mapping is invoked in standard mode, the execution of the mapping body is skipped and the null value is returned to the caller. by In strict mode, failure to evaluate the when clause as a pre-condition causes the mapping execution to fail. In contrast in standard mode, failure to evaluate the when clause as a guard causes execution of the mapping body to be skipped and null to be returned to the caller. In 8.2.1.21 Correct The map and xmap keywords may be called on a listcollection as source In 8.2.1.22 Correct where the <resolve_op> is one of the following: resolve, resolveone, invresolve, and invresolveone. In 8.2.1.22 Correct When isDeferred is true the latelate keyword is used before the operation name<resolve_op>. In 8.2.1.22 Correct The resolution operator may be called on a listcollection. This is a shorthand for invoking it in the body of a ForExpan xcollect ImperativeIterateExp expression. In 8.2.1.22 Replace // shorthand for mylist->forEach(i) { i.late resolve(Table); } by // shorthand for mylist->xcollect(late resolve(Table)) Actions taken: December 27, 2012: received issue December 22, 2015: Resolved March 29, 2016: closed issue Discussion: Help wanted. Disposition: Deferred End of Annotations:===== m: webmaster@omg.org Date: 27 Dec 2012 05:49:35 -0500 To: Subject: Issue/Bug Report X-Brightmail-Tracker: AAAAAA== X-Brightmail-Tracker: AAAAAA== ******************************************************************************* Name: Christopher Gerking Employer: mailFrom: cgerking@campus.upb.de Terms_Agreement: I agree Specification: Meta Object Facility (MOF) 2.0 Query/View/ Transformation Specification Section: 8.2.1.15 MappingOperation FormalNumber: formal/2011-01-01 Version: 1.1 Doc_Year: 2011 Doc_Month: January Doc_Day: 01 Page: 93 Title: No trace data for disjuncting mapping Nature: Clarification Severity: Significant CODE: 3TMw8 B1: Report Issue Description: Trace data creation is specified to happen "at the end of the initialization section". For disjuncting mappings, the initialization section is never executed, which prevents any trace data from being stored. As a consequence, no resolution via resolve-in-expressions is possible on the disjuncting mapping, due to the missing trace record. This is problematic, since disjunction should be transparent from a resolver's point of view, i.e. it should not make a difference for resolution whether a mapping disjuncts or not. Hence, some clarification is required whether trace records are deliberately avoided for disjuncting mappings (for whatever reason), or whether trace data must be created in another place than the init section in case of a disjuncting mapping.