Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

Difference between revisions of "QVTd Traces and Invocations"

(Trace interfaces)
(Invocation statuses)
Line 129: Line 129:
  
 
Ambiguity, if multiple overrides succeed, is the status successful for all/any? Is the possibility of a multiple success a static error?
 
Ambiguity, if multiple overrides succeed, is the status successful for all/any? Is the possibility of a multiple success a static error?
 +
 +
Each overridden relation requires a not-predicate on all the overriding relations incurring a quadratic reification cost in QVTc that we would like to avoid at run-time. The overrides form a tree (in QVTr but more generally a singly rooted acyclic directed graph). The tree nodes can be labelled breadth first with the label maintained in the AbstractInvocation to track progress. The Connection dispatcher treats the tree as a state machine for the search for the matching override. This can be an efficient implementation, but we cannot easily express it in QVTc; leave it for the QVTi connection synthesis to discover it.
  
 
===Trace classes===
 
===Trace classes===

Revision as of 16:17, 20 August 2017

The QVT specification of QVTc trace class synthesis for QVTr transformations is very thin. This document considers the real requirements.


This working document takes over from

QVTr specification oversights

Overrides

QVTc has no support for overriding and so overriding must be synthesized during the QVTr2QVTc transformation.

A simple synthesis requires two actions.

  • callee-side, each overridden relation has an AND of when-not-predicate on each of the transitively overriding relations
  • caller-side, each call of an override has an OR of all possible overriding relations

Non-top Relations

QVTc has no support for non-top mappings consequently a non-trivial synthesis of an X_Y mapping is suggested to accommodate the Y relation after X. This scales quadratically when X or Y has overrides.

Better to synthesize an invocation class produced by the caller and consumed by the callee. To accommodate overriding a hierarchy of invocation classes and interfaces is needed.

Statuses

A when/where predicate may involve complex boolean expressions involving the value of many RelationCallExp instances.

This can be accommodated if the trace class includes a status property denoting success/fail/not-ready. The run-time execution must ensure that a fail status is assigned implicitly; success can be assigned explicitly.

Implicit when's

RelationCallExp's in when predicates are synchronous

  • invoker starts
  • invoker initiates when calls
  • invoker waits for when returns
  • invoker resumes

RelationCallExp's elsewhere in Boolean expressions such as

where { if A(x,y) then B(x,y) else C(x,y) endif; }

make a synchronous (implicit-when) call of A(x,y).

Not a particular problem once the assumption of trivial predicates is removed.

CollectionTemplateExp traces

QVTr2QVTc omits CollectionTemplates. It is therefore unclear whether the collection and/or members and rest should be traced.

A fundamental requirement is that the trace should facilitate an incremental re-execution.

The members and rest can be deduced from the overall collection or vice-versa. So there might be a free design choice.

However anonymous members/rest are only interesting wrt existence rather than value, so members/rest offers significant space saving opportunities.

Temporarily the overall collection is more consistent with ObjectTemplateExp tracing.

Trace Packaging

The QVTr specification defines the basic naming and typing of trace Classes and Properties. It ignores Packages, Models and URIs.

Packages, Models and URIs are also a bit troublesome for QVTr/QVTc too. Eclipse QVTr therefore simplifies a Transformation to be just a Class and to require a conventional Model/Package hierarchy ancestry.

Trace Property opposites

OCL's opposites are fundamental to the reification of traceability by QVTc trace classes. However opposites are ignored by the trace class synthesis.

The opposite naming is trivial.

The opposite multiplicity requires careful consideration of whether the non-opposite occurs below a 1:N navigation.

For edogeneous transformations, a further complication arises with domain identification.

The Eclipse QVTr trace therefore has Ecore EAnnotations to fully characterize the opposites.

Eclipse QVTr solutions

The synthesized trace comprises

  • a Model
  • a Package per (typically one) Transformation
  • a trace Class per Relation/Mapping
  • a trace Property per traced Variable
  • a status Property for tested progress
  • an invocation Class per non-top Relation
  • trace/invocation interface Classes for overriding Relation/Mapping
  • infrastructure Classes

The Package URI is configurable.

Package, Class, Property names are derived from Transformation, Relation, Variable names.

Invocation classes

Each non-top not-overridden relation has an invocation class to reify its invocation in QVTc.

The invocation class extends AbstractInvocation which is contained by the AllInvocations class.

Each invocation of a non-top not-overridden relation realizes an instance of the invocation class.

Each root variable is bound by a property in the invocation class.

For when invocations a further initially null property is assigned the trace class instance after successful/failed execution.

Execution occurs when the invoked (top) mapping responds to the invocation class instance and assigns its trace to the invocation.

Invocation interfaces

Each non-top overridden relation has an invocation class and an invocation interface to reify its invocation in QVTc.

The invocation interface inheritance inverts the overrides hierarchy with AbstractInvocation at the root. "inverts" since the least overridden relation is applicable to all overrides.

Each invocation class extends its corresponding invocation interface.

Each invocation of a non-top overridden relation realizes an instance of the invocation class.

Each root variable is bound by a property in the invocation class.

The properties are typed and hosted by the interface of the least overridden relation to which they apply. Pattern matching within the overriding relation checks/converts the overridden types to the overriding types.

For when invocations a further initially null property is assigned the trace class instance after successful/failed execution.

Execution occurs when the invoked (top) mapping responds to the invocation class instance and assigns its trace to the invocation. The derived invocation class selects only those overrides of the invoked relation. The invoked mapping matches its interface in order to consider only viable overrides. Internal not-predicates inhibit execution when an override succeeded.

Invocation statuses

Invocation statuses are only needed for explicit and implicit when invocations. The invocation class property is assigned to the trace of the mapping that executed.

Ambiguity, if multiple overrides succeed, is the status successful for all/any? Is the possibility of a multiple success a static error?

Each overridden relation requires a not-predicate on all the overriding relations incurring a quadratic reification cost in QVTc that we would like to avoid at run-time. The overrides form a tree (in QVTr but more generally a singly rooted acyclic directed graph). The tree nodes can be labelled breadth first with the label maintained in the AbstractInvocation to track progress. The Connection dispatcher treats the tree as a state machine for the search for the matching override. This can be an efficient implementation, but we cannot easily express it in QVTc; leave it for the QVTi connection synthesis to discover it.

Trace classes

Each not-overridden relation has a trace class to reify the execution of the corresponding mapping.

The trace class has property for each 'bound' variable; separate issue; the status necessary fir incremental execution.

Invocation occurs when a matching pattern of input objects binds to the root variable, one of which is an invocation class instance for a non-top invocation.

Invocation creates the trace class instance.

If the invocation is a when invocation, an additional status property is assigned true on successful execution, or false after an unsuccessful (predicate failed) execution. The when-invoker may use this status.

Trace interfaces

Each overridden relation has a trace class and interface to reify the execution of the corresponding mapping.

The trace interface inheritance repeats the overrides hierarchy with AbstractTrace at the root.

Each trace class extends its corresponding trace interface.

Each invocation (root variables match) of an overridden relation creates an instance of the invocation class.

For when invocations a further initially null property is assigned true/false after successful/failed execution.

The concrete trace class is created by the executing mapping. The interface is accessed by the caller primarily to test success, but possibly to test the enforced result. The status is provided by AbstractTrace. The non-root variables can be accurately typed in the leaf concrete class.

The root variables could be accurately typed in each leaf concrete class with a hierarchy of accurately typed get-operations to support access from the interface.

Alternatively the root-variables could be provided with least overridden type in the least overridden interface. No operations needed, but some run-time type discovery/checking may be needed.

Design decision: all trace properties (other than the status) in the concrete trace class. Hierarchy of get-operations for the root variables in the trace interfaces.

(In UML, perhaps derived/redefined properties might work directly, but in Ecore we need the get-operations.)

Trace statuses

Bound Variables

QVTr's definition of bound variables is vague, particularly for Collections.

Hidden variables

Template patterns are nominally single property descent, but initializers may be arbitrary expressions such as a.b.c. If we only trace a, then chnages to a.b or a.b.c escape incremental re-evaluation. If the trace is QVTs-derived rather than QVTr-derived this hazard could be avoided. Possibly even for a.b(c).

Collection variables

Consider tracing the OrderedSet{first ++ _} pattern against a simple Family::children : OrderedSet(Person). For the family {a,b,c}.

The residue is irrelevant so the single trace of {a} is adequate to detect a change in a. Addition of {a,b,c,d} is irrelevant.

But tracing Set{child ++ _} against Family::children : Set(Person) now has three traces {a}, {b}, {c} and a further trace is needed if d is added.

Back to the top