Hi
Things are less regular if every mapping is not an implicit
disjunction and tranbsitively so. Hopefully the follwoing is ok.
Regards
Ed Willink
Replace Section 8.1.13 with the following text to be placed
before the current 8.1.12.
8.1.12 Mapping Overloading
Invocation of a mapping selects a disjunction of one or more candidate
mapping's at compile time. At run-time, the first
matching candidate mapping is selected and invoked.
The disjunction may be specified explicitly using the disjuncts
keyword or implicitly by an overloaded mapping.
8.1.12.1 Explicit Disjuncts
In the following example, the explicit disjunction defines convertFeature
as a disjuncting mapping name that may be invoked on a
UML::Feature with a Boolean argument. convertAttribute,
convertConstructor and convertOperation are candidate
mapping names.
mapping UML::Feature::convertFeature(asUpper: Boolean) : JAVA::Element
disjuncts convertAttribute, convertOperation, convertConstructor {}
mapping UML::Attribute::convertAttribute(asUpper: Boolean) : JAVA::Field {
name := if asUpper then name.toUpper() else name endif;
}
mapping UML::Operation::convertConstructor(asUpper: Boolean) : JAVA::Constructor
when {self.name = self.namespace.name;} {
name := if asUpper then name.toUpper() else name endif;
}
mapping UML::Operation::convertOperation(asUpper: Boolean) : JAVA::Constructor
when {self.name <> self.namespace.name;} {
name := if asUpper then name.toUpper() else name endif;
}
The explicit disjuncts causes the mapping invocation
to successively assess the implicit and explicit predicates of convertAttribute,
convertConstructor and convertOperation to
identify the first match. If no match is found the mapping
invocation returns null.
The explicit predicates are provided by arbitrary constraints
specified in when clauses. Implicit predicates are
provided by the type signatures; each source and argument must
conform to the type of the corresponding candidate mapping
parameter.
The candidate return type must be covariant, that is
the same as, or derived from that of, the disjuncting
return type to ensure that no result incompatibility arises.
Since the argument types contribute to implicit predicates, the
candidate parameter types may be supertypes or subtypes
of the disjuncting mapping parameter type. The number
of candidate and disjuncting parameter types
must be the same.
An explicit candidate mapping is identified by its mapping
identifier which may contribute to more than one
disjunction.
8.1.12.2 Implicit Disjuncts
An implicit disjunction groups overloaded mappings. One mapping
overloads another when the overloading source type extends the
overloaded source type and when the overloading and overloaded
mappings have same name and parameter count. Every mapping
declaration establishes an implicit disjunction of itself and
all its overloads, which may be in an extending transformation.
When UML::Attrbute and UML::Operation
extend UML::Feature, the previous example may be
simplified to use an implicit disjunction.
mapping UML::Feature::convertFeature(asUpper: Boolean) : JAVA::Element {}
mapping UML::Attribute::convertFeature(asUpper: Boolean) : JAVA::Field {
name := if asUpper then name.toUpper() else name endif;
}
mapping UML::Operation::convertFeature(asUpper: Boolean) : JAVA::Constructor
when {self.name = self.namespace.name;} {
name := if asUpper then name.toUpper() else name endif;
}
mapping UML::Operation::convertFeature(asUpper: Boolean) : JAVA::Constructor
when {self.name <> self.namespace.name;} {
name := if asUpper then name.toUpper() else name endif;
}
he explicit disjuncts provides distinct names and so
facilitates explicit calls direct to the candidate
mappings. The implicit disjuncts requires no disjuncting
declaration and so faciltates extension by addition of further
contributions.
8.1.12.3 Disjunct candidates
All mappings with the required name, parameter count and
matching or derived source type are candidate mapping's
for the invocation of a disjuncting mapping. This
includes mappings inherited from extended transformations. The candidate
mapping's referenced in a disjuncting mapping
may introduce new names and consequently a further disjunction
of candidate mapping's; the explicit disjunct is
transitive.
For instance invocation of convertFeature for a Property
in the explicit disjuncts example should consider a Property::convertOperation(Boolean)
inherited from an extended transformation since the explicit
disjunct adds convertOperation to the transitive
candidates. Conversely, the implicit disjunct example considers
only candidates whose signature is convertFeature(Boolean).
For standard evaluation, a deterministic selection order for
evaluation of the predicates of the candidates as guards is
established by sorting using the following proritized criteria.
A distinction by an earlier criteria overrules all later
criteria.
- directly invoked explicitly disjuncted candidate mappings
are evaluated in declaration order
- mappings in the current transformation are selected before
those in an extended transformation, then mappings in an
extended transformation before those in an extended extended
transformation, and so forth
- mappings for a more derived type are selected before those
for a less derived type
- mappings are prioritized by alphabetical mapping name order
- mappings are prioritized by alphabetical context type name
order
- mappings are prioritized by alphabetical context type
containing package name order, then by containing package
containing package name order, and so forth
The ordering above ensures that an extending transformation can
occlude a mapping in an extended transformation and that a
mapping for a derived type occludes that for a base type. (An
implementation may use static analysis of the predicates to
eliminate occluded candidates completely and to provide reduced
candidate lists according to the source type of the mapping
invocation.)
For strict evaluation, the same ordering applies but the first
candidate for which the source type conforms is selected without
evaluating the predicate as a guard. The predicate is instead
evaluated as a pre-condition giving an assertion failue when not
satisfied.
In 8.2.1.15 Replace
Resolving the mapping call implies finding the operation to
call on the basis of the actual type of the source (self
variable). This follows usual object-oriented virtual call
semantics.
by
Resolving the mapping call implies building a prioritized list
of candidate mapping's then selecting the first candidate
mapping for which, using standard invocation mode, all
predicates are satisfied. For strict invocation mode, the first
candidate mapping for which the source object (self
variable) conforms to the context type is selected and
predicates are executed as pre-conditions. If no candidate
mapping is identified, null is returned to all
results. Building the prioritized candidate mapping
list is described as part of the Mapping Overloading description
in Section 8.1.12.
In 8.2.1.16 Delete
Executing mappings defined as disjunction of other mappings
An invocation of a mapping operation defined as a disjunction of
other mapping operations is done in two steps: firstly,
the guards of the disjuncted mappings are executed in sequence
until one of the guards succeeds. If no guard succeeds, the
null value is immediately returned. Otherwise, the body of the
mapping which guard has succeeded is executed. The
signature of the disjuncting mapping must conform to the
signature of the disjuncted mappings, following ordinary
constraints between the caller and the callee. Specifically, the
result of the disjunction needs to be a super type of the
result type of the composed mappings.
On 12/10/2015 09:22, Christopher
Gerking wrote:
Hi
You
are talking about an explicit disjuncts, and we agree on
that case. I’m referring to a dynamic dispatch without an
explicit disjuncts, where I see one crucial difference.
For
an explicit disjuncts, the disjuncting mapping and the
disjunct candidates have (in general) heterogeneous
signatures: types are compatible but the mapping name is
usually different. Otherwise, if names were equal as well,
there would be no need for disjuncts and we could use a
simple dynamic dispatch. Provided that the signatures are
heterogeneous, it is very obvious which mapping is actually
called. If the caller requires a trace record for the
disjuncting mapping, he should call the disjuncting mapping
explicitly, and not any of the disjunct candidates (even if
the invoked candidate is already known statically).
Without
an explicit disjuncts, the situation is different. Mapping
names are equal, so any B::doIt might be invoked more or
less accidentally, without producing a trace record for
A::doIt. Therefore I propose that resolveIn(A::doIt)
internally retrieves resolveIn(B::doIt) as well, for any
B::doIt known as a dynamic dispatch candidate. This should
be an internal mechanism, no additional user effort. And
there is no need for 100 trace records to accomplish this.
If
there would be an implicit dynamic dispatch in your example
(no explicit disjuncts), I disagree with respect to the
resolve behavior. See below.
var b : B := Object B {... }
b.map doIt() -> Static call on B:::doIt() (-> create
trace record)
Dynamic call on B::doIt() (->
trace record already created)
b.resolveIn(A1::doIt) <> null
b.resolveIn(A2::doIt) <> null
...
b.resolveIn(A100::doIt) <> null
b.resolveIn(B::doIt) <> null
b.resolveIn(C::doIt) = null
Based
on your approach, changing the declaration from b:B to b:A1
would change the resolve behavior. This will confuse users.
I think that the declared variable types should affect the
visible behavior of a transformation as little as possible.
In case of disjuncts, changing from B to A1 would (in
general) require a change to a different called mapping as
well, because of the usually heterogeneous mapping names. If
the user declares an explicit disjuncts without a need (as
in your example), then he is responsible himself for the
affected behavior.
I
see therefore a crucial difference between
disjuncts/dispatch, and I wonder if it is really possible to
unroll any dynamic dispatch in terms of a static disjuncts.
Regards
Christopher
Hi
Christopher,
I think you are not looking close enough to the disjunct
relationship direction. I said "100 mappings disjuncting
B::doIt()", so B::doIt doesn't "act as dynamic dispatch" in
any case. I can still be clearer/more specific/precise with
the example, though. Please have a look to the following:
mapping A1::doIt() : AA disjuncts B::doIt, C::doIt { ... }
mapping A2::doIt() : AA disjuncts B::doIt, C::doIt { ... }
...
mapping A100::doIt() : AA disjuncts B::doIt, C::doIt { ... }
mapping B::doIt() : BB {...}
mapping C::doIt() : CC {...}
Having B and C (no inheritance relationship between B and C)
inheriting A1, A2, ... A100 (no inheritance relationship
between the different A1, A2... A100 )
If you have :
var a1 : A1 := Object B {... }
a1.map doIt() -> Stactic call on A1::doIt() (-> create
trace record)
Dynamic call on B::doIt() (->
create another trace record)
the object hold by var a1 should be traced on an BB object,
through the mappings A1::doIt() and B::doIt(), therefore the
following boolean expressions must hold:
a1.resolveIn(A1::doIt) <> null
a1.resolveIn(A2::doIt) = null
...
a1.resolveIn(A100::doIt) = null
a1.resolveIn(B::doIt) <> null
a1.resolveIn(C::doIt) = null
If you have :
var b : B := Object B {... }
b.map doIt() -> Static call on B:::doIt() (-> create
trace record)
Dynamic call on B::doIt() (->
trace record already created)
the object hold by var b should be traced on an BB object,
through JUST the mapping B::doIt(), therefore the following
boolean expressions must hold:
b.resolveIn(A1::doIt) = null
b.resolveIn(A2::doIt) = null
...
b.resolveIn(A100::doIt) = null
b.resolveIn(B::doIt) <> null
b.resolveIn(C::doIt) = null
Sorry, but I'd need a concrete and strong real world example
to convince me that what I've exposed above is not right.
Have a nice weekend !!
Cheers,
Adolfo.
On 09/10/2015 15:35, Christopher Gerking
wrote:
No.
If there are 100 mappings and B::doIt acts as dynamic
dispatch candidate for all of them, I expect all possible
resolveIn(… ::doIt) calls to consider B::doIt as well. No
need for 100 trace records, but the one existing record
should be taken into account in all 100 cases.
IMHO
the statically known type of an object shouldn’t affect
the subsequent resolveIn behavior. If there is a dynamic
dispatch on invocation, there should be an inverse dynamic
“recipience” on resolve.
Hi
Christopher,
Well, since statically is known, a text-hover can highlight
which mapping you are (statically) calling.
The problem is the direction of the relationship. Let me
clearly expose the point with another example:
If there are 100 mappings disjuncting B::doIt(), are you
going to create a 101 trace records, when just one B::doIt()
mapping call took place ?... Surely not
Regards,
Adolfo.
On 09/10/2015 12:49, Christopher
Gerking wrote:
Hi
Adolfo
Yes,
I recognized your point only after sending my last
message.
Again
I can’t come up with a real example. But I could imagine
that there is a number of :A instances and doIt() is
called on all of these. If (for whatever reason) some of
the :A is known as :B on invocation, a subsequent
resolveIn(A::doIt) will return null in these cases.
To
circumvent this behavior we would need
b.oclAsType(A).map doIt() in order to ensure that
A::doIt is consulted first. That’s quite a burden for
users, because the difference between a call to A::doIt
and a call to B::doIt is totally invisible in the CS.
I
propose to define the resolveIn behavior in such a way
that candidate mappings for a dynamic dispatch are
considered as well.
Regards
Christopher
Hi All,
Ed: After doing a quick excercise in Eclipse QVTo, The
only "shortcoming" I can oversee to the new addition (the
disjuncting mapping body can be executed), is the
following:
mapping EClass::m1() : EClass
disjuncts EClass::m2, EClass::m3{}
There is a backwards compatibility issue, because now m1
mapping, would return an EClass rather than null. Note
that, even though you don't define init/population
section, the object would be created.
Providing that "default" disjuncts mapping could still be
created by the transformation designer, I'd not push
forward that semantic modification for a mapping disjunct.
Christopher: I mentioned my point of view for your
example, perhaps you missed it/it was not clear.
Summarizing:
b : B;
b.doIt();
Should statically invoke B::doIt() (the disjuncted
mapping)
Therefore, A::doIt() is not invoked
Therefore, IMO opinion, b.resolveIn(A::doIt) should return
null rather than the object created by B::doIt().
Another comment, traces are needed at the moment in which
the mappings are executed for both, disjuncting and
disjuncted mapping, because if you only rely on tracing
the disjuncting mapping and the disjuncted mappings have
guards, and the original object is modified (inout model),
you won't be able to accurate know which disjuncted
mapping was actually been executed (if you try to discover
that when evaluating the resolveIn _expression_).
Regards,
Adolfo.
On 09/10/2015 10:20, Ed Willink
wrote:
Hi
Christopher
My suggestion that the disjuncting body replaces the
currently null no-match default seems more elegant; no
built in null, an opportunity to define a useful 'null'
behavior. But if anyone dislikes it, the status quo is
adequate.
QVT13-23 is one that I want to resolve this weekend. See
List and Dict thread for requested table of current
practical usage.
Regards
Ed Willink
On 09/10/2015 09:09, Christopher
Gerking wrote:
Hi
Should
there be a “disjuncting body” or not? Eclipse QVTo
enforces statically that there is none. Where are
the advantages/disadvantages?
With
respect to the tracing, I prefer trace records for
both disjuncting and candidate mappings. See
http://solitaire.omg.org/issues/task-force/QVT13-23.
Eclipse
QVTo does that already.
I
would like to understand the tracing behavior for
dynamic dispatch. If there is some ‘a’ known as :A,
and a.doIt() is called, a trace record for A::doIt
should be obviously created. If ‘a’ is actually :B
and there is a dynamic dispatch, then another trace
record for B::doIt should be created as well.
But
what happens if there is some ‘b’ known as :B and we
call b.doIt(). Clearly there is a trace record for
B::doIt, but what about A::doIt?
No
matter how many trace records are created, I think
that b.resolveIn(A::doIt) should work. Instead of
creating multiple trace records, another option
would be to make the resolveIn more sensitive: when
calling b.resolveIn(A::doIt), trace records for the
candidate B::doIt could be considered as well.
Regards
Christopher
Hi
Thanks. Three interesting points. We have 6 days
before this gets semi-frozen in a Preview.
It is not my intention to require any
run-time functionality to move to comple-time. I think
I just highlight that unspecified but necessary
functionality is at run-time.
The "usual object-oriented virtual call semantics" is:
execute the function corresponding to the derived
type.
My suggested MappingCallExp semantics is a prioritized
(run-time) disjunct search:
if A's predicates are satisfied doA
else if B's predicates are satisfied doB
...
else null
I observe that some static analysis can eliminate some
of the cases. (In the case of unknown transformation
extension, the static analysis could be at load-time,
or JIT for each new invocation.)
In your example perhaps your internal doIt' is my
internal list of candidates. Reifying the internal
list may make the exposition clearer.
---
Given a body for both candidate and disjuncting
mapping, when is each executed? Perhaps the
disjuncting body (default null) is executed only when
no candidate is found.
---
If a MappingCallExp.referredOperation references
X::doA, it is currently unspecified in OCL and so in
QVTo whether this invokes precisely X::A or the
overload applicable to the actual source type. In OCL
it should nearly always be the overload, though just
occasionally as in super-calls it would be nice to
suppress dynamic dispatch. Perhaps a Boolean
isStaticDispatch flag is needed and set by the
presence of a fully qualified name in the source code.
If a MappingCallExp used the "usual object-oriented
virtual call semantics" then it is precisely the same
problem. But it's different although with the same
ambiguity. Does the the AS reference to X::A trigger
the disjunct search for X::A or just call X::A
regardless? Mostly it should do the disjunct search,
but just X::A if we want a super-call. (A more
optimized implementation looks up the precomp[uted
source type specific list of candidate mappings.)
---
Tracing has a similar problem.
Is the disjuncting mapping traced or is the actual
selected candidate mapping traced? Both are of some
use. See my AMT 2015 talk. The most important usage is
in resolveIn where the user cannot sensibly reference
the candidate mapping, therefore resolveIn must at
least work for a reference to the disjuncting mapping.
However, particularly given that a candidate mapping
may actually be candidate for multiple disjuncting
mappings, it should also be possible to invoke
resolveIn with respect to the actual candidate
mapping. This is probably difficult and hard to
support unless the trace record contains both
disjuncting and candidate mapping identities. Both are
needed internally, an arbitrary choice could be made
for the qvttrace file for which the QVTo specification
might evolve to dismiss as a proprietary convenience.
Certainly nothing that is QVTr compatible and fully
supporting incremental re-execution.
Regards
Ed
On 07/10/2015 11:31, Adolfo
Sanchez-Barbudo Herrera wrote:
Hi Ed,
In principle, the implicit disjuncts seems a good
idea, an there are some interesting clarifications
in your proposal, but I need to point out a couple
of concerns.
1. The disjuncting mapping itself is a kind of
"intermediate" mapping (no logic goes there). So in
your example:
mapping A::doIt() : AA {...}
mapping B::doIt() : BB {...}
mapping C::doIt() : CC {...}
The equivalent should be something like the following:
mapping A::doIt'() : AA
disjuncts B::doIt, C::doIt, A::doIt {...}
mapping A::doIt() : AA {...}
mapping B::doIt() : BB {...}
mapping C::doIt() : CC {...}
At
compilation time any static call to A::doIt(),
should be changed to the A::doIt'()
2. More seriously, you are moving a run-time
dispatch mechanism, to a compile-time, which it
should turn to be reflected in the AS. That in
principle sounds OK for single transformations, i.e.
for inter-transformation mappings extensions, but it
doesn't seem so good in the inter-transformation
reuse scenario, because we need cross-references
from the extended transformation to the different
extending ones. Compiled transformations wouldn't
make less sense, or we would require many AS
compiled copies/variants of a extended
transformation, depending on how these implicit
disjuncts come up from the extending ones.
I reluctant to replace the traditional virtual
mapping call mechanism (performed at runtime) by
this new implicit disjuncts mechanism (performed at
compile time). That said, I think that much of what
you have tried clarify, can be useful explain for
instance, how signature of extending mappings should
be, or how the virtual mapping call mechanism should
be performed in QVT rather than "This follows usual
object-oriented virtual call semantics" (page 93) .
I hope you find my comments useful.
Regards,
Adolfo.
On 07/10/2015 10:41, Ed Willink
wrote:
Hi
A first attempt at a proposal. I think it says
what is needed, but perhaps some of it should be
moved/duplicated in 8.2.1.21 MappingCallExp.
I considered "abstract" since it is in the
Concrete Syntax and another issue requests it. I'm
not sure whether it is really that useful.
Regards
Ed Willink
Replace Section 8.1.13 with the following text
to be placed before the current 8.1.12.
8.1.12 Mapping Overloading
Invocation of a mapping selects a disjunction
of one or more candidate mappings at
compile time. At run-time, the first matching
candidate mapping is selected and
invoked. The disjunction may be specified
explicitly using the
disjuncts keyword or implicitly by an
overloaded mapping.
8.1.12.1 Explicit Disjuncts
In the following example, the explicit
disjunction defines convertFeature
as a
disjuncting mapping name that may be
invoked on a UML::Feature with a
Boolean argument. convertAttribute,
convertConstructor and
convertOperation are candidate
mapping names.
mapping UML::Feature::convertFeature(asUpper: Boolean) : JAVA::Element
disjuncts convertAttribute, convertOperation, convertConstructor {}
mapping UML::Attribute::convertAttribute(asUpper: Boolean) : JAVA::Field {
name := if asUpper then name.toUpper() else name endif;
}
mapping UML::Operation::convertConstructor(asUpper: Boolean) : JAVA::Constructor
when {self.name = self.namespace.name;} {
name := if asUpper then name.toUpper() else name endif;
}
mapping UML::Operation::convertOperation(asUpper: Boolean) : JAVA::Constructor
when {self.name <> self.namespace.name;} {
name := if asUpper then name.toUpper() else name endif;
}
The explicit disjuncts causes the
mapping invocation to successively assess the
implicit and explicit predicates of
convertAttribute, convertConstructor
and convertOperation to identify the
first match. If no match is found the mapping
invocation returns
null.
The explicit predicates are provided by
arbitrary constraints specified in
when clauses. Implicit predicates are
provided by the type signatures; each source
and argument must conform to the type of the
disjuncting mapping. An abstract
mapping has a false implicit
predicate; an abstract mapping cannot be
executed.
The candidate return type must be
covariant, that is the same as, or derived
from that of, the
disjuncting return type to ensure
that no result incompatibility arises.
Since the argument types contribute to
implicit predicates, the candidate
argument types may be supertypes or subtypes
of the
disjuncting mapping. The number of candidate
and disjuncting argument types must
be the same.
An explicit candidate mapping is
identified by its mapping identifier which
identifier may contribute to more than one
disjunction.
8.1.12.2 Implicit Disjuncts
An implicit disjunction groups overloaded
mappings. One mapping overloads another when
the overloading source type extends the
overloaded source type and when the
overloading and overloaded mappings have same
name and argument count.
When UML::Attrbute and UML::Operation
extend UML::Feature, the previous
example may be simplified to use an implicit
disjunction.
mapping UML::Feature::convertFeature(asUpper: Boolean) : JAVA::Element {}
mapping UML::Attribute::convertFeature(asUpper: Boolean) : JAVA::Field {
name := if asUpper then name.toUpper() else name endif;
}
mapping UML::Operation::convertFeature(asUpper: Boolean) : JAVA::Constructor
when {self.name = self.namespace.name;} {
name := if asUpper then name.toUpper() else name endif;
}
mapping UML::Operation::convertFeature(asUpper: Boolean) : JAVA::Constructor
when {self.name <> self.namespace.name;} {
name := if asUpper then name.toUpper() else name endif;
}
he explicit disjuncts provides distinct names
and so facilitates explicit calls direct to
the
candidate mappings. The implicit
disjuncts requires no disjuncting
declaration and so faciltates extension by
addition of further contributions.
8.1.12.3 Disjunct candidates
All mappings with the required name, argument
and matching or derived source type are
candidate mappings for the invocation
of a disjuncting mapping. This
includes mappings inherited from extended
transformations. The
candidate mappings referenced in a disjuncting
mapping may introduce new names and
consequently a further disjunction of
candidate mappings; the explicit
disjunct is transitive.
For instance invocation of convertFeature
for a Property in the explicit
disjuncts example should consider a
Property::convertOperation(Boolean)
inherited from an extended transformation
since the explicit disjunct adds
convertOperation to the transitive
candidates. Conversely, the implicit disjunct
example considers only candidates whose
signature is
convertFeature(Boolean).
For non-strict evaluation, a deterministic
evaluation order for evaluation of the
predicates of the candidates as guards is
established by sorting using the following
proritized criteria. A distinction by an
earlier criteria overrules all later criteria.
-
directly invoked explicitly disjuncted
candidate mappings are evaluated in
declaration order
-
mappings in the current transformation are
evaluated before those in an extended
transformation, then mappings in an extended
transformation before those in an extended
extended transformation, and so forth
-
mappings for a more derived type are
executed before those for a less derived
type
-
mappings are prioritized by alphabetical
mapping name order
-
mappings are prioritized by alphabetical
context type name order
-
mappings are prioritized by alphabetical
context type containing package name order,
then by containing package containing
package name order, and so forth
The ordering above ensures that an extending
transformation can occlude a mapping in an
extended transformation and that a mapping for
a derived type occludes that for a base type.
An implementation may use static analysis of
the predicates to eliminate occluded
candidates completely and to provide reduced
candidate lists according to the source type
of the mapping invocation.
For strict evaluation, the same ordering
applies but the first candidate for which the
source type conforms is selected without
evaluating the predicate as a guard. The
predicate is instead evaluated as a
pre-condition giving a
null return when not satisfied.
In the QVTo model and Fig 8.3. Add
MappingOperation ::isAbstract : Boolean[1]
default false.
In 8.2.15 MappingOperation Attributes Add
isAbstract : Boolean[1]
Indicates whether the mapping is abstract,
requiring an overload for all derived context
types. Default is false.
On 06/10/2015 13:26,
Christopher Gerking wrote:
Hi
+1 for choosing the most derived in case of a family of overloaded mappings.
I also like the approach of defining an overload as an implicit disjuncts. In particular, this could simplify the traceability recording rules.
When calling a.doIt() dispatches to B::doIt(), I expect a traceability record for a.resolveIn(A::doIt), even if A::doIt didn't really execute.
For disjuncts, Eclipse QVTo already records traceability links also for the disjuncting mapping. Therefore the above requirement would be fulfilled.
It is more interesting when we have b:B and call b.doIt(). Does it still consult A::doIt() and produce the traceability link for b.resolveIn(A::doIt) ?
Regards
Christopher
-----Ursprüngliche Nachricht-----
Von: qvto-dev-bounces@xxxxxxxxxxx [mailto:qvto-dev-bounces@xxxxxxxxxxx] Im Auftrag von Ed Willink
Gesendet: Sonntag, 4. Oktober 2015 13:30
An: QVTOML developer mailing list <qvto-dev@xxxxxxxxxxx>
Betreff: [qvto-dev] What are the mapping refinement rules
Hi
When preparing my "QVT Traceability : What does it really mean?"
presentation to AMT 2015, I was forced to think hard about mapping signatures and their relationships.
https://www.eclipse.org/mmt/qvt/docs/ICMT2014/QVTtraceability.pdf
http://www.slideshare.net/EdWillink/qvt-traceability-what-does-it-really-mean
Declaratively, independent mappings are all invoked independently, dependent mappings such as refinements are arbitrated by their predicates to select the best of a group of related mappings.
Imperatively, it is much simpler, mappings are explicitly invoked, so exactly one compatible mapping is invoked per source object.
The simplest case is the invoked name corresponds to a declared mapping.
More interesting, the invoked name corresponds to a disjuncted mapping allowing the best match of the explicit disjuncts to be invoked, else null.
I am unclear about what happens when the invoked name corresponds to a family of 'overloaded' mappings analoguous to Java operation overloads.
e.g.
mapping A::doIt() : AA {...}
mapping B::doIt() : BB {...}
mapping C::doIt() : CC {...}
where C and B extend A
I presume that in QVTo we choose the most derived analoguously to Java.
I'm inclined to clarify this situation by defining such overloads as implicit disjuncts, so that all colliding names contribute to a disjunct
The example is then equivalent to
mapping A::doIt() : AA
disjuncts B::doIt, C::doIt {...}
mapping B::doIt() : BB {...}
mapping C::doIt() : CC {...}
This could make disjuncts extensible since an extending transformation could supply additional name collisions for the explicitly/implicitly disjuncted mapping.
In order to give deterministic dispatch, the order of disjuncts is:
explicit disjuncts first, then implicit disjuncts successively ordered by the following criteria
- most derived source type,
- most derived first argument type,
- most derived second argument type,
- etc
- alphabetically by containing class name,
- alphabetically by containing class' containing package name,
- etc
The signatures of refinements are unclear. Since a mapping is explicitly invoked, we clearly require that disjuncting mappings have the same number, position and direction of arguments and a covariant
(same/derived) return type. (An explicit disjunct may omit trailing in
arguments.)
Since we are invoking mappings with predicates rather than invoking operations, we may allow disjuncting mappings to also have covariant or even contravariant arguments. When a disjuncting mapping has a distinct in/inout argument type, it is equivalent to an oclIsKindOf() when predicate for that argument type with a subsequent oclAsType() in the body.
Regards
Ed Willink
_______________________________________________
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
_______________________________________________
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: 4435/10768 - Release Date: 10/06/15
_______________________________________________
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
_______________________________________________
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: 4435/10773 -
Release Date: 10/07/15
_______________________________________________
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: 4435/10783 -
Release Date: 10/08/15
_______________________________________________
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
_______________________________________________
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
_______________________________________________
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
_______________________________________________
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: 4435/10803 - Release
Date: 10/12/15
|