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

QVTd In-place and Copy Transformations

Revision as of 13:42, 18 March 2017 by Ed.willink.me.uk (Talk | contribs) (QVTi implications)

The QVT specification has vague indications that QVTr / QVTc supports in-place transformations but provides no real details.

Copy transformations in which the output is very similar to the input are not considered at all.

This working document considers how copy and in-place might be supported. It takes over from

The Use Case

Support an EcoreUtil.Copier-like capability:

  • deep copy of an input model
  • arbitrary input classes, some of which may use an extension metamodel not known until run-time
  • references to copied class instances are redirected to the copies
  • references to external class instances reference the unchanged external class instance

QVTr solution

Impossible, since there is no ability to create a dynamically determined type.

Even if all classes are known at programming time, it is necessary to enumerate an explicit copy of each class. See the

-- copy an ocl expression
-- For space reasons this relation is not expanded out here

at the end of the RelToCore example.

QVTc solution

Impossible, since there is no ability to create a dynamically determined type.

Copy versus In-Place transformation

These could be treated as separate challenges, but from a programmer perspective they are identical; a potentially late run-time option can specify whether the output overlays or replicates the input. We therefore treat copy and in-place as the same problem when considering UMLX, QVTr, QVTc. THe distinction may perhaps occurs as alternate qvts2qvti synthesizes generate different code, or perhaps just in the qvti run-time.

Copy versus non-copy transformation

A non-copy transformation specifies all created types explicitly. Output slots are populated explicitly.

A copy transformation can re-use the source type/object as the target type/object. Output slots may be populated implicitly (by copy/re-use).

Using a non-copy language semantics for a copy requires all slots to be enumerated to participate in the copy. This is verbose and error prone.

An alternative copy language semantics need only specify deviations from a perfect deep copy. cf. Henshin's create/delete markups.

QVTc / QVTr copy semantics

QVTr is realized by a QVTr2QVTc transformation, so it is really the QVTc copy semantics that we must resolve.

Derived types

QVTc cannot create/re-use a derived type. A variant realize, a typeof operator or a template type could re-use the dynamic type, but we must also deep copy all the slots that are not assigned explicitly. Is a copy except a list of properties needed? Is it possible to perform a global transformation analysis to identify the except properties automatically? Is it necessary to defer to a run-time capability that automatically deep copies what isn't explicitly assigned? How would a run-time capability know to perform the late deep copies if multiple mappings collaborate in the assignments?

A copy-except-list-of-properties makes the problem a programmer responsibility, so it can be right. A WFR can detect some conflicts between the except-list and the actual assignments. This is similar to a WFR that can detect missing assignments.

The copy-except can be defined more positively as a CopySignature, rather like a QVTr Key; the name of a copied base-type and the names of the properties that are to be assigned explicitly, rather than copied automatically. realize xInstance:XClass using XCopySignature.

Copy Trace Classes

A copy needs a simple 'trace' comprising XCopySignature{in:X; out:X} allowing navigation such as 'myIn.XCopySignature.out'.

How does the copy trace relate to the mapping trace?

For a simple mapping that creates a copy the mapping trace could inherit/aggregate the copy trace.

For a more complex mapping that create more than one copy, the corresponding multiple inheritance is only an option under normal OO semantics with careful renaming, unfortunately EMF always imposes diamond inheritance. Multiple aggregation is possible. Without inheritance, does a copied object have separate navigations using the mapping trace class and the copy trace class?

Derived copy-trace classes

One CopyTrace declaration may extend another CopyTrace declaration to extend the number of not-deep-copied properties. It has no effect on the copied class which is always the same as the source.

Incremental Copy

If an obscure property in a derived copied class is changed, then an incremental copy must re-copy. How does a trace that is unaware of this property handle it? Possibly any mutation of the source triggers a full copy. Possibly the trace has an 'anything-else' so that known properties are handled efficiently, only unknown properties get the anything-else treatment.

Multiple Copy Signatures

What if a class has two distinct refined copy mappings?

Each should have a distinct copy-signature and so there should be two possible navigations.

What if a multiply inherited class inherits multiple copy mappings?

Each should have a distinct copy-signature and so there should be multiple possible navigations. The base copy traces may navigate to distinct objects. The more derived copy traces may (redundantly) navigate to the same object.

Normal multiple inheritance and casting could allow shared references, but EMF won't support it so we will need the bloat of all possibilities.

Internal/External references

A direct implementation of a reference copy must make a two-way decision as to whether the mapping navigates through the trace object of the copied internal source object, or just re-uses the external source object. Provided the trace object navigation support a Boolean test capability for existence this test is possible but messy.

We cannot eliminate the trace of the internal, but we can add a copy-trace for the external thereby ensuring that all references always use a copy-trace, even if the external trace is degenerate with identical source/target objects; just as an in-place might also have. This makes the QVTc much more regular and so simplifies the QVTr2QVTc synthesis.

QVTr copy syntax

ModelMorf

ModelMorf introduces a replace keyword that may qualify a relation to support in-place. Unfortunately I do not understand the description in the Readme.htm of its Beta-4. Perhaps there is some similarity with the domain declaration proposed below.

Transformation declaration

Applying a magic copy keyword to the transformation declaration could change the semantics/syntax but how might a transformation that needs a bit of copy and a bit of non-copy select between semantics. Seems too coarse grained.

Relation declaration

Applying a magic copy keyword to the relation declaration is more flexible but limiting for examples such as the TTC PetriNet2Statechart that need to trans form a pair of domains in-place.

Relation inheritance

Copy semantics could be inherited if default copy relations are auto-generated and available for re-use by derived relations. Unfortunately QVTr overrides is a replace rather than augment capability, so this would need changing. It is not clear how this handles types not known at programming time.

Absolute Domain declaration

Applying a magic copy keyword to the domain declaration creates a problem that there are then pairs of domains with the same name. The intuitive WFR could be relaxed.

Relative Domain declaration

A copies xxxx clause could suffix a domain declaration to indicate that the new domain is based on a copy of the xxxx domain.

Within the copy domain we can exploit the multi-rooted capability to require that all root-variables of the copy domain have names that appear in the copied domain. The copy domain therefore defines one or more Henshin-like overlay patterns; a pattern for creation, an equals null for deletion.

A very similar effect could be achieved by adding a mutation { ... } clause to the copied domain. This is slightly shorter and avoids a duplicated name, but adds to the brace syntax complexity of domains, wheres and collections.

QVTc copy syntax

QVTs implications

Copy

A realized node may be

  • created with the specified type (current functionality)
  • created/re-used with a referenced type with a selective deep copy

The new usage adds a copy-trace middle element in addition to the mapping-trace middle element. The type of the copy-trace corresponds to a copy signature and so a list of not-deep-copied properties.

In-place

We need extra edges to enforce the write-after-read re-use.

We probably don't need extra caching since the middle model caches anyway.

QVTi implications

Use Case Solution

QVTr

copy-key MyTypeKey{isCopy};
copy-key MyDerivedTypeKey extends MyTypeKey{isCopy2}

relation UseACopy {
    domain model1
        c1 : MyContext {
            t1 : MyType {}
        }
    domain model2
        c2 : MyContext {
            t2 : MyType {}
        }
    when {
        MakeABaseCopy{t1, t2);
    }
}   
 
relation MakeABaseCopy {
    domain model1
         t : MyType {};
    domain model2 copies model1 using MyTypeKey
         t { isCopy = true; };
}    
 
relation MakeADerivedCopy overrides MakeABaseCopy {
    domain model1
         t : MyDerivedType {};
    domain model2 copies model1 using MyDerivedTypeKey
         t { isCopy = true; isCopy2 = true; };
}    

QVTc

mapping UseACopy {
    domain model1(t1 : MyType){}
    domain model2(t2 : MyType | t1.TMakeABaseCopy.out = t2){
}   
 
mapping MakeABaseCopy {
    domain model1(t : MyType){};
    domain model2 copies model1
         realize t2 := ;
}    
 
mapping MakeADerivedCopy overrides MakeABaseCopy {
    domain model1(t : MyDerivedType){};
    domain model2 copies model1
         t { name = t.name.toLower(); };
}    

Back to the top