Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [qvto-dev] QVT 1.3 Traceability proposal

Hi Christoher

Thanks. You've picked up the kind of detail I wanted you to. Are you sure that you are happy that the trace needs deep clones?

Comments inline.

    Regards

        Ed Willink

On 12/10/2015 14:34, Christopher Gerking wrote:

Hi

 

Well done. Some comments below.

 

 

“This relationship can be queried by the execution of another mapping”.

 

I disagree. Resolving has no side-effects, so it should be possible to access trace data also from other types of operations like queries or helpers.

 

Yes.

 

“This including any mappings executed by accessed or extended transformations or libraries”.

 

I basically agree. But what does this mean for resolving from within an accessed transformation? Is the trace data from the accessing transformation available? So is there an immediate write-through? That’s dangerous, because if one transformation accesses two other transformations (which share some mapping operations), the second transformation might fall over trace records created by the first one.

 

Alternatively, an accessed transformation could start with an empty trace data. At the end of the nested execution, there would be a write-back to the trace of the accessing transformation. I consider this as the most generally compatible solution.

 

Overall, the initial trace data should depend on whether the accessed transformation reuses the model extents from the accessing transformation. But I think this would imply too many hybrid forms and twilight areas for a clean specification.

 

Maybe I don't understand accessed transformations. I thought they were a variant of extended transformations with different name visibility rules. In both cases there is just one 'TransformationCallExp' and so only one trace data. I see no actual 'TransformationCallExp'to enable one transformation to invoke another.

 

“The trace record is created […] at the start of the initialization section of the selected candidate mapping.”

 

That’s earlier than before. I see the advantage that some unnecessary re-executions can be prohibited, but only if one and the same mapping is re-executed (directly or indirectly) from within in its own init section. Are there other advantages in creating the trace record earlier?

If it's at the end of init, what happens with assertion failures...? It seesm that start of init is the boundary between deciding what to do, whether it has already been done and doing it, so this is where the prohibition on a retry is created.

Please make the case for an alternative / explain why Eclipse QVTo does something different.

 

“The initially null value of the out-parameters and result-parameters fields is updated at the end of the candidate mapping execution.”

 

Does “at the end” mean after the end section? That’s later than it was before. The problem is that the change excludes the possibility of calling resolveIn(M) from within the body of M. That’s a pity because the results do already exist. So why not resolving them, even if uninitialized?

 

The problem is that re-use of previous values must be the final previous values, not the interim previous values. If necessary the trace record results could be initialized at the end of init and updated at the end of termination.

 

“These queries return the sequence of target objects.”

 

Should the order of that sequence be specified?

 

Yes, in mapping execution order.

 

“However if multiple resolutions are available, the assertion is that there is at most one resolution is not satisfied and execution fails”.

 

That’s quite an influential change. I see the advantages. However I wonder if there are too many situations where resolveone(…) is used as a plain shortcut for resolve(…)->first() or resolve(…)->any(…). Especially when using resolveone(OCL-condition), the expected result could often be any random object that satisfies the condition, even if there are more than one candidates. Also expressions like resolveone(EClass) are quite silly, because there will be more than one EClass in almost any case.

 

Both resolve(...)->first() and resolve(...)->any() have a different problem; invalid for an empty Sequence.

Strong/weak resolveone is a design choice. The behaviour of forOne is clearly weak, so weak is appropriate for resolveone too; we can define it as the first if there is one.

 

“The ordering in which late resolutions occur does not matter, since each late resolution can influence only its own deferred assignment.”

 

But the execution order of the assignments does matter. Especially in case of opposite references. Can local variables be used to “buffer” lateresolve results for re-access in a subsequent lateesolve? Don’t underestimate the assignment order.

This contributes to why I tend to use a Dict rather than a resolve. Given a two pass transformation, the first pass trace cannot be used in pass 1; too soon, but can be used in pass 2. The late resolve cannot be used in pass 1 or pass 2, since late resolution occurs after all mappings are complete.

There is a design choice:

a) imperative 1: late resolutions are resolved in mapping execution order with assignments updated accordingly, possibly deferring again for a second late resolution. Later mapping executions can exploit the value of a late resolve in not particularly predictable fashion.

b) imperative 2: late resolutions are resolved in deferred assignment order with multiple late resolutions occurring to suit the assignment evaluation. Later mapping executions can exploit the value of a late resolve in not particularly predictable fashion.

c) Declarative: All assignment RHSes are computed; no cross use of late resolutions is possible. Then all assignments are done. Predictable but never helpful.

I chose c). Make the case for a) / b) / something else.

 

 

“The body of the disjuncting mapping is not executed.”

 

There shouldn’t be a body, as you described right below.


Agreed? or do you want a textual tweak?

 

 

Kind regards

Christopher

 

Von: qvto-dev-bounces@xxxxxxxxxxx [mailto:qvto-dev-bounces@xxxxxxxxxxx] Im Auftrag von Ed Willink
Gesendet: Montag, 12.
Oktober 2015 12:57
An: QVTOML developer mailing list <qvto-dev@xxxxxxxxxxx>
Betreff: [qvto-dev] QVT 1.3 Traceability proposal

 

Hi

My proposed resolution to clarify tracing and resolution is below.

Please read carefully. The clarifications impose some subtly stronger requirements. The tracing of DataType values implies deep cloning in ways that I thought would be correct but unacceptable. But looking at the QVTo implementation it appears that EValue clones.

    Regards

        Ed Willink

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 by the execution of another mapping using one of the eight resolve operations.

8.1.x.1 Trace Records

Execution of a transformation builds the overall trace data which comprises a sequence of trace record; one for each mapping execution. This including any mappings executed by accessed or extended transformations or libraries. Each trace record comprises:

  • context-parameter - the context (or source) 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 (and inout) parameter objects or values
  • result-parameters - the result (or target) parameter object or objects

The invoked-mapping and executed-mapping operations may differ when a disjuncting mapping is invoked. The invoked-mapping is the disjuncting mapping. The executed-mapping is the successfully selected candidate mapping or null.

inout parameters are traced twice, once as in-parameters and again as out-parameters.

The trace record is created with context-parameter, in-parameters, invoked-mapping and executed-mapping fields at the start of the initialization section of the selected candidate mapping. This is after predicates have been executed as guards or pre-conditions. The initially null value of the out-parameters and result-parameters fields is updated at the end of the candidate mapping execution. In the case of a standard mode execution for which no candidate mapping is selected, the trace record contains null entries for executed-mapping, out-parameters and result-parameters fields.

The trace record traces the source/target relationship; it does not trace object construction or helpers. If a trace is needed, these untraced facilities must be wrapped up inside a mapping.

8.1.x.2 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 further restricted to those mapped from a particular source object by supplying the source object as the context object.

    source.resolve(Table);

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.

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))->flatten() in
selectedTargets->selectByKind(TYPE)->select(T | CONDITION)

8.1.x.3 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 operation.

    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.

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))->flatten() in
selectedTargets->selectByKind(TYPE)->select(T | CONDITION)

8.1.x.4 invresolve() - Resolution of source objects by Type or Mapping

The corresponding inverse queries identifying source objects conforming to a given type or mapping is available using the invresolve or invresolveIn operations.

    target.invresolve(t : Table | t.name.startsWith('_'));
    target.invresolveIn(Class2Table, t : Table | t.name.startsWith('_'));

8.1.x.5 resolveone() - Resolution of a single source or target object by Type or Mapping

The four resolveone variants of the four resolve operations modify the return to suit the common case where only a single object is expected. The normal return is therefore the resolved object or null. However if multiple resolutions are available, the assertion that there is at most one resolution is not satisfied and execution fails,.

    source.resolveone(t : Table | t.name.startsWith('_'));
    source.resolveoneIn(Class2Table, t : Table | t.name.startsWith('_'));
    target.invresolveone(t : Table | t.name.startsWith('_'));
    target.invresolveoneIn(Class2Table, t : Table | t.name.startsWith('_'));

8.1.x.6 Late resolution

The resolve operations query the prevailing state of the trace data. resolve cannot therefore return results from mappings that have yet to execute. This may require careful sequencing of mapping execution. Alternatively a late keyword may prefix the resolve when the resolve 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. 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.7 Redundant execution

The trace data is used to suppress re-execution of any previously executed mapping in favor of the previous execution.

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 is 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. The out-parameters and result-parameters fields of the previous execution are re-used as the corresponding returns of the re-execution attempt.

8.1.x.8 Persisted Trace Data

The trace data may be persisted and reloaded to support a re-execution. However since the trace record does not trace multiple object states, configuration data, transformation context or intermediate data, it is not possible to use a persisted form of the trace data to support incremental re-execution of an arbitrary QVTo transformation. A well-behaved transformation that avoids mutating objects 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 Correct

There are threetwo reuse and composition facilities 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

A disjuncting mapping operation may be defined as an explicit disjunction of candidate mapping operations. This means selecting and executing the first candidate mapping whose when clause and other predicates are satisfied. The body of the disjuncting mapping is not executed. An implicit disjunction of candidate mappings is formed by overloaded mappings with matching name and argument count.

The execution semantics subsection below provides the details of these reuse facilities.

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 first define the semantic of the execution of a mapping operation in absence of any inheritance or merge reuse facility, then we describe the effect of using these facilities.

n 8.2.1.21 Replace

Indicates the mode of the mapping invocation.

by

Indicates 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 ForExp _expression_.

In 8.2.1.22 Replace

// shorthand for mylist->forEach(i) { i.late resolve(Table); }

by

// shorthand for mylist->xcollect(late resolve(Table))

 



_______________________________________________
qvto-dev mailing list
qvto-dev@xxxxxxxxxxx
To change your delivery options, retrieve your password, or unsubscribe from this list, visit
https://dev.eclipse.org/mailman/listinfo/qvto-dev


No virus found in this message.
Checked by AVG - www.avg.com
Version: 2015.0.6140 / Virus Database: 4447/10805 - Release Date: 10/12/15



Back to the top