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 Relation Overriding"

(The QVTr2QVTc synthesis)
(The QVTr2QVTc synthesis)
Line 39: Line 39:
 
The synthesis of the alternator mapping must treat predicates differently since only a total failure may fail. Individual predicate failures must set the state of corresponding trace class state.
 
The synthesis of the alternator mapping must treat predicates differently since only a total failure may fail. Individual predicate failures must set the state of corresponding trace class state.
  
- identify all polymorphic 'calls' - top/when/where
+
* identify all polymorphic 'calls' - top/when/where
- identify distinct polymorphisms - an alternator for each
+
* identify distinct polymorphisms - an alternator for each
- build 'inheritance' tree/lattice - trace class per leaf
+
* build 'inheritance' tree/lattice - trace class per leaf
- gather trace class properties from each polymorphic element
+
* gather trace class properties from each polymorphic element
- synthesize alternator for predicates of each polymorphic element
+
* synthesize alternator for predicates of each polymorphic element
- apply CSE
+
* apply CSE
- synthesize each polymorphic element using its alternator trace class as predicate
+
* synthesize each polymorphic element using its alternator trace class as predicate
 +
 
 +
===Aggregated predicates===
 +
 
 +
Aggregating the predicates highlights a problem. What if a predicate involving a when succeeds, but its result is unsatisfactory. For the particular case of a type check, the required type could be pushed into the invocation. But for a more general case where perhaps two when's are invoked and their results checked for inequality, how is each 'successful' when invocation ignored? Not even speculation will cope with code that rejects the full results. Prohibiting rejectable when's seems too strong a limitation.
 +
 
 +
Another problem. The alternator may need to be multi-stage in order to avoid unnecessary invoking when predicates that are occluded by successful overrides.

Revision as of 16:08, 16 May 2017

The QVT specification has a relatively clear specification that QVTr relation may override, but no clues as to how this is mapped to QVTc that has no overrides concrete syntax, even though it inherits an overrides capability from QVTb.

This working document considers how overriding might be supported. It takes over from

QVTc Choices

QVTc refinement syntax is an additive capability and therefore not suitable for implementing the QVTr replacement semantics of QVTr overrides.

We could add overrides syntax and semantics to QVTc, which then passes the buck to QVTi. But since we already need an 'alternator' to dispatch multiple similar but differently predicated mappings efficiently, we may be able to kill two birds with one stone.

QVTc is relatively simple. It solves the mapping sequencing problem by inter-trace class references/dependencies. Can it solve the overrides problem as-is? Let's go with this.

The low level / run-time mechanism

(Temporarily ignoring the additional complexities of multi-headed mappings.) When an element is dequeued from a Connection, it is dispatched to all relevant mappings. This remains true for overrides. Predicates and type guards will suppress most irrelevant invocations, but we must suppress overrides. There will often be only one appropriate mapping, but we cannot avoid the possibility that the input model has new compound types that are multiply matched. We cannot avoid a multiplicity of matches and a lattice of fall-backs for failed predicates.

The original motivation for an alternator was to avoid repetition. If the alternator hoists all predicate functionality from all dispatch candidates, we maximize sharing, and can resolve all the fall-backs before 'returning' with the list of actual dispatches.

Perhaps the alternator is a function that is invoked as the predicate of each override. Possible because the failed predicates should participate in a decision tree. But how to pass context.

If the alternator is a mapping, it has a trace class that can have all the required shared content. The overrides just predicate the alternator-trace-class and its magic decision variables. Simple override choices may use a simple alternator class to avoid bloating the alternator trace with all the context for every awkward choice. The alternator therefore conditionalizes its realized trace variable. But QVTc only conditionalizes by using one mapping per type which destroys the whole purpose. The QVTc alternator must create a ragbag of all possibilities. Optimizing this to exclude default valued-elements will have to be a QVTs/QVTi optimization.

The QVTc mechanism

For each distinct polymorphic dispatch there is a single alternator mapping that hoists the predicates of all possible targets and encodes the dispatch decision, perhaps as a few Booleans, perhaps as an Enumeration, ... . Each dispatch target uses the alternator trace as its predicate with appropriate matches on the decision.

What about an override that participated in multiple distinct polymorphic dispatches?

Simple case, one is a super-type of the other. Re-use the larger ragbag, but provide distinct alternators to avoid run-time computation bloat.

Horrible case, multiple inheritance. Simple solution, ragbag the lot. More optimum, multiple trace class inheritance.

The QVTr2QVTc synthesis

The alternator trace ragbags all the mapping predicates. For each mapping predicate we get a Boolean go/no-go, which may need to be reified in the alternator trace for run-time dispatch. Where we can prive that some of these Booleans are orthogonal we can compress to an Enumeration of orthogonal alternatives.

The synthesis of the alternator mapping must treat predicates differently since only a total failure may fail. Individual predicate failures must set the state of corresponding trace class state.

  • identify all polymorphic 'calls' - top/when/where
  • identify distinct polymorphisms - an alternator for each
  • build 'inheritance' tree/lattice - trace class per leaf
  • gather trace class properties from each polymorphic element
  • synthesize alternator for predicates of each polymorphic element
  • apply CSE
  • synthesize each polymorphic element using its alternator trace class as predicate

Aggregated predicates

Aggregating the predicates highlights a problem. What if a predicate involving a when succeeds, but its result is unsatisfactory. For the particular case of a type check, the required type could be pushed into the invocation. But for a more general case where perhaps two when's are invoked and their results checked for inequality, how is each 'successful' when invocation ignored? Not even speculation will cope with code that rejects the full results. Prohibiting rejectable when's seems too strong a limitation.

Another problem. The alternator may need to be multi-stage in order to avoid unnecessary invoking when predicates that are occluded by successful overrides.

Back to the top