Open eclipse-qvt-oml-bot opened 1 day ago
By Christopher Gerking on Oct 22, 2015 06:41
(In reply to Adolfo Sanchez-Barbudo Herrera from comment #0)
I didn't find any example for 5) and 6) and probably they should not be supported. Rationale: If a library doesn't define model parameters (some comments about this below), we won't probably be able to instantiate an accessed transformation or extend it.
There seems to be no point in a library reusing a transformation. But is it necessarily invalid?\
11) "A library may declare an ordered list of model types on which it operates. This list is the signature of the library." (Page 83). Interpretation of this is aligned with one of the Christopher comments: "A library doesn't have ModelParameters". If there are no model parameters, two comments: a) Library "signature" is confusing. b) Indeed, a library can always be implicitly instantiated without hassles (we don't need to pass model extents to it). c) Helpers and mappings should then be prohibited in libraries (see 10)) because if an element is created we don't know to which model extent should belong
That was a quick shot from my side, maybe I was wrong and libraries do require model parameters. If so, a binding for the model parameters should be specified for the respective ModuleImport.
However, even if libraries don't have model parameters, then mappings or helpers should still be allowed. That's because a library operation is always invoked in the context of a base transformation, regardless of access or extents. Therefore the model parameters of the base transformation are available at runtime, and can be inferred automatically as target extent of a certain mapping. The @extent declaration is optional for a mapping, so why should mappings be prohibited entirely if there are no model extents? Of course they can't refer to a particular target model, but they can always exist without.
The crucial question is: do we require the @extent notation at all? I think no, because it applies to the rare case of root elements only. What I would prefer instead is to determine the root elements of a model explicitly:
transformation t(out myExtent : myModelType);
main {\ myExtent += x.map m();\ }
12) One could interpret, that a library is just a non-invokable OperationalTransformation, but this interpretation might be in conflict with other possible interpretations e.g. a library should not contain helpers and mappings.
I think that a library is basically a non-invokable transformation. Libraries can contain mappings and helpers.
13) Conceptually the StdLib is just a simple Library which is implicitly imported. But how is that library defined ? Are all the operations defined as side effects-full helpers or side effects free queries? What about operations like clone which create elements ? Are we in contradiction of 10) providing that helpers or mapping might not be allowed in a library ?
Yes, we are. Side-effects should be allowed.
14) "When a library is imported with access semantics, an implicit instance is created and used to access the properties and operations of the library" (Page 83) and "With access semantics, the definitions of the imported module are not inherited by the importing module. Hence an instance of the imported module has to be used in order to access them. In the case of accessing a library, an instance of the imported module is implicitly available" (Page 85). We have this concept of "implicit" instance which needs to be accessed: "use" or "access" the "implicit" instance is confusing. Accessing the instance is necessary if there is any property or non-contextual operation to be accessed. Perhaps, when accessing a library, you can only invoke contextual imperative operations. If you need to access or invoke a non-contextual property of a library, you need to "extend" it rather than "access" it.
I think there's a misunderstanding. There aren't so many differences between accessing and extending a library. When a library is accessed, its (contextual) operations can be invoked right away. The "not inherited" was interpreted by Eclipse QVTo in such a way that these operations can't be overridden, as opposed to extending the library. They are invokable nevertheless. Thus if you don't override operations, there is no difference between accessing and extending a library.
I'm uncertain about the consequences of the above "access" restriction: should an operation override attempt give a syntax error in case of access?
By Adolfo Sanchez-Barbudo Herrera on Oct 22, 2015 11:01
Hi Christopher,
Thanks for your helpful comments. I mostly agree with them, specially with the introduction of Orphan elements in the next specification version (if the issue resolution finally goes through!). Therefore, I don't see the need to prohibit helpers and mapping operations in libraries neither: it's not strictly mandatory that a created element ends up in a model extent.
Having this dichotomy and all these "issues" for just having a non-executable transformation doesn't sound clever. Would it make any practical difference, allowing parameter-less transformations that can't be executable instead. Anyway, I'm not gonna persuade to a Library concept removal ;). I presume that not having to declare model-paremeters is a plus for defining libraries with reusable operations/properties.
More importantly, I also think that the specification is not so wrong. Good.
Some other comments in-lined below.
The thread discussion will follow up in a separate/new comment
Cheers,\ Adolfo.
(In reply to Christopher Gerking from comment #1)
(In reply to Adolfo Sanchez-Barbudo Herrera from comment #0)
I didn't find any example for 5) and 6) and probably they should not be supported. Rationale: If a library doesn't define model parameters (some comments about this below), we won't probably be able to instantiate an accessed transformation or extend it.
There seems to be no point in a library reusing a transformation. But is it necessarily invalid?
Extension: Indeed, no point. It should be invalid, the libraru could end up inheriting an entry operation.\ Access: I see no conceptual problem of having a library instantiating a transformation. However, unless there is a mechanism to create model extents, you can't ever instantiate a transformation from a library, because the latter doesn't have model parameters. I'd not go in this direction. For the time being, invalid.
That was a quick shot from my side, maybe I was wrong and libraries do require model parameters. If so, a binding for the model parameters should be specified for the respective ModuleImport.
However, even if libraries don't have model parameters, then mappings or helpers should still be allowed. That's because a library operation is always invoked in the context of a base transformation, regardless of access or extents. Therefore the model parameters of the base transformation are available at runtime, and can be inferred automatically as target extent of a certain mapping. The @extent declaration is optional for a mapping, so why should mappings be prohibited entirely if there are no model extents? Of course they can't refer to a particular target model, but they can always exist without.
The crucial question is: do we require the @extent notation at all? I think no, because it applies to the rare case of root elements only. What I would prefer instead is to determine the root elements of a model explicitly:
transformation t(out myExtent : myModelType);
main { myExtent += x.map m(); }
mapping X::m() : Y@myExtent { ... }
If you don't put @myExtent, but the modelExtent can be inferred (as occurs in this example, because you only have one model parameter), the created element would still end up as a root element of your model.
myExtent.addElement(x.map m());
I think that a library is basically a non-invokable transformation. Libraries can contain mappings and helpers.
Perfect. Plus the addition that a library doesn't define model parameters, the just declare the model types used inside the library.
14) "When a library is imported with access semantics, an implicit instance is created and used to access the properties and operations of the library" (Page 83) and "With access semantics, the definitions of the imported module are not inherited by the importing module. Hence an instance of the imported module has to be used in order to access them. In the case of accessing a library, an instance of the imported module is implicitly available" (Page 85). We have this concept of "implicit" instance which needs to be accessed: "use" or "access" the "implicit" instance is confusing. Accessing the instance is necessary if there is any property or non-contextual operation to be accessed. Perhaps, when accessing a library, you can only invoke contextual imperative operations. If you need to access or invoke a non-contextual property of a library, you need to "extend" it rather than "access" it.
I think there's a misunderstanding. There aren't so many differences between accessing and extending a library. When a library is accessed, its (contextual) operations can be invoked right away. The "not inherited" was interpreted by Eclipse QVTo in such a way that these operations can't be overridden, as opposed to extending the library. They are invokable nevertheless. Thus if you don't override operations, there is no difference between accessing and extending a library.
I think that when you say "its (contextual) operations", if you are excluding non-contextual operations and properties, then I think we agree. At the end the differences are exactly the same as they happen in OOP. When talking about class inheritance, you can call an operation/access a field right away from the deriving class. On the contrary, when talking about class composition, you need to refer to an instance of the composed class to call any of its method/access any of its fields from the composing one.
In practice, in qvto this means:
As I think we agreed, as of the current specification, you can't refer to non-contextual operation or properties defined defined in it. In essence, since the library instance is implicit and you can'r refer it, you can't access those operations and properties.
If you have two conflicting operations (same op name, conformant parameter types, etc) in two libraries you want to import, you can't reuse them when inheriting, however you could still reuse those libraries when accessing, because you should have two different instances of those libraries and be able to explicitly invoke the method you want.
Note: Since the contextual operations should be available without accessing the (implicit) instance of an accessed library, what I said before doesn't apply: both libraries couldn't be imported as access, because they have two conflicting contextual operations.
From another perspective, contextual operations are invoked on an instance of the contextual type, therefore, it should not make any different if we are importing via access or inherits.
So far we have been talking about libraries. I'd like to see your opinion, if all contextual operations are available if a transformation access another transformation. In other words, should the purpose of accessing transformations just be executing the whole transformation. This could provide another subtle difference between a library and a transformation.
I'm uncertain about the consequences of the above "access" restriction: should an operation override attempt give a syntax error in case of access?
I don't think so:
Cheers,\ Adolfo.
By Adolfo Sanchez-Barbudo Herrera on Oct 22, 2015 11:26
With all of this apparent agreement, I think there are a couple of problems in the specification. Particularly when we have that a ModuleImport refers to some ModelType bindings.
The possible scenarios\ (In reply to Adolfo Sanchez-Barbudo Herrera from comment #0)
1) Transformation access Transformation (e.g. in Page 71) 2) Transformation extends Transformation (e.g. in Page 71) 3) Transformation access Library (e.g. in Page 82) 4) Transformation extends Library (e.g. in Page 82) 5) Library access Transformation 6) Library extends Transformation 7) Library access Library (e.g. in Page 83) 8) Library extends Library (e.g. in Page 83)
Comments about the different scenarios.
1) In principle, no big problems. Instantiation of the accessed transformation needs to be explicit: When we do "new x(a,b)" we can declare king of binding between the accessing transformation and the accessed one. Therefore in the ModuleImport declaration, the bound ModelTypes can be understood as both transformations are working with the "compatible" model types. Let's not get\ Minor problem An instantiation expression should refer to a constructor when passing arguments. Shouldn't have a transformation have an implicit constructor definition ?
2) Important problem. The AS relates to ModelTypes bindings, however we need a way to relate model parameters from the extending transformation to the extended one. ModuleImport::binding is not enough.
3) and 7) Minor problem. An implicit instance of the accessed library is created. In principle OK, but as commented if the accessed library had non-contextual operations and properties we can't access them.
4) and 8) No problems. We don't have the issue we had at 2). Libraries are model-parameter less, therefore a simple declaration of ModelType bindings, to ensure they are working with "compatible" model types, should be enough. No need for ModelParameter bindings.
5) 6) As commented in my previous post, this should probably be invalid ModuleImport declarations.
I have some possible solutions, but let's firstly argue which are genuine problems, before flooding the thread with more info.
Cheers,\ Adolfo.
By Ed Willink on Oct 22, 2015 12:12
At the risk of adding confusion.
It would help to have a rationale for why a Library is less than a Transformation. With Christopher's nested modular Transformations I am far from clear that a Library could not contain sub-transformations.
Perhaps the only useful difference is an expectation that a Library is loaded from a pre-compiled e.g. .qvtoas whereas a Transformation is loaded from a e.g. .qvto.
By Adolfo Sanchez-Barbudo Herrera on Oct 22, 2015 12:47
Hi Ed,
From the the point of view of the AS, I'd say:
a) OperationalTransformation contains ModelParameters, Library doesn't.\ b) Although is not clear in the metamodel (Module::entryOperation should probably be OperationTransformation::entryOperation), a Library should NOT refer to an EntryOperation. See 8.2.1.2 Library:
"However, in contrast with operational transformations there is no main operation to execute and the instantiation of the class is always implicit"
In any case, just because of a), a Library should not be allowed to link with "sub-transformations". i.e. a Library doesn't have the model parameters required by a "sub-transformation" (regardless the former acceses or extends the latter). Therefore 5) and 6) => invalid.
Regards,\ Adolfo.
By Christopher Gerking on Oct 23, 2015 04:53
(In reply to Adolfo Sanchez-Barbudo Herrera from comment #2)
Perfect. Plus the addition that a library doesn't define model parameters, the just declare the model types used inside the library.
Where's the difference? Once accessed/extended, the declared model types would be bound to particular model params of the accessing/extending transformation.
I think that when you say "its (contextual) operations", if you are excluding non-contextual operations and properties, then I think we agree.
I didn't exclude non-contextual operations, so it seems as if we disagree.
- As I think we agreed, as of the current specification, you can't refer to non-contextual operation or properties defined defined in it. In essence, since the library instance is implicit and you can'r refer it, you can't access those operations and properties.
The library instance is implicitly available. This doesn't imply that it is not referenceable. If contextual operations are available (and can be invoked on a context object), why should contextless operations be unavailable? They just don't require a context and therefore should be invocable without a context object. I see no difference.
From another perspective, contextual operations are invoked on an instance of the contextual type, therefore, it should not make any different if we are importing via access or inherits.
- For contextual operations, as commented, I think there should be no difference if you are importing them or accessing them. So you should be allowed to override them in both cases.
No. There's a crucial difference that applies to both contextual and contextless operations. Imagine a library A which defines an operation A::o() and invokes o() in other places. It doesn't matter if o() is contextless or contextual. If B extends A and provides an equivalent B::o(), it overrides A::o() such that all invocations of o() inside A will actually execute B::o(). In contrast, there is no override if B accesses A. It just hides the A::o() in favor of B::o(). Invocations of o() from within A will still execute A::o().
By Ed Willink on Oct 23, 2015 05:27
(In reply to Christopher Gerking from comment #6)
No. There's a crucial difference that applies to both contextual and contextless operations. Imagine a library A which defines an operation A::o() and invokes o() in other places. It doesn't matter if o() is contextless or contextual. If B extends A and provides an equivalent B::o(), it overrides A::o() such that all invocations of o() inside A will actually execute B::o(). In contrast, there is no override if B accesses A. It just hides the A::o() in favor of B::o(). Invocations of o() from within A will still execute A::o().
Obviously operation overloading is not specified (in QVTo or OCL). Not even a throwaway "uses standard OO semantics". http://solitaire.omg.org/browse/QVT13-136 raised.
OCL is going Java-like which is what QVTo might be assumed to do too. But for your example, I consider that access/extension semantics affects the names that are visible at compile-time, but it makes NO difference to the operations invoked at run-time. ALL packages and operations are merged in a simple obvious crunch. Collisions are resolved in favour of an extending rather than extended module.
By Adolfo Sanchez-Barbudo Herrera on Oct 23, 2015 07:09
(In reply to Christopher Gerking from comment #6)
(In reply to Adolfo Sanchez-Barbudo Herrera from comment #2)
Perfect. Plus the addition that a library doesn't define model parameters, the just declare the model types used inside the library.
Where's the difference? Once accessed/extended, the declared model types would be bound to particular model params of the accessing/extending transformation.
A model transformation can have 100 model parameters, all of them referring to just 1 model type. So to mere there is a difference. If a module declares model parameters, you have to bind model parameters rather than model types. So:
Does this make sense ?
I think that when you say "its (contextual) operations", if you are excluding non-contextual operations and properties, then I think we agree.
I didn't exclude non-contextual operations, so it seems as if we disagree.
- As I think we agreed, as of the current specification, you can't refer to non-contextual operation or properties defined defined in it. In essence, since the library instance is implicit and you can'r refer it, you can't access those operations and properties.
The library instance is implicitly available. This doesn't imply that it is not referenceable. If contextual operations are available (and can be invoked on a context object), why should contextless operations be unavailable? They just don't require a context and therefore should be invocable without a context object. I see no difference.
Contextless operations actually have a context, the own transformation/library.
You don't need to explicitly refer to object (this/self) to invoke a contextless transformation, if and only if they are invoked in the own module. However, if you are accessing another module, you need to refer to the "implicit instance" to be able to invoke them.
As I said before, just think of OOP, and the same applies to any property (e.g. intermediate contextual property) you have for the transformation. If you extends, you can do "myProperty", if you access you should do "implicitInstance.myProperty"
If advancing the solution, helped to understand my point. The idea is giving the possibility of providing a name for the "implicit instance" of the accessed module:
---- lib1.qvto ----
library l1;
helper helloWorld() : String = "Hello World";
---- lib2.qvto ----
library l2;
helper helloWorld() : String = "Hello World2";
---- lib3.qvto ----
import lib1.qvto;\ import lib2.qvto;
library l3\ access a : l1,\ access b : l2\ ;
helper helloWorld() : String {\ return a.hellowWorld() + b.helloWorld();\ }
No. There's a crucial difference that applies to both contextual and contextless operations. Imagine a library A which defines an operation A::o() and invokes o() in other places. It doesn't matter if o() is contextless or contextual. If B extends A and provides an equivalent B::o(), it overrides A::o() such that all invocations of o() inside A will actually execute B::o(). In contrast, there is no override if B accesses A. It just hides the A::o() in favor of B::o(). Invocations of o() from within A will still execute A::o().
"A::o() and invokes o() in other places. It doesn't matter if o() is\ contextless or contextual."
Of course it does matter, because the operation will be called on different kind of objects.
There should only be just one difference between a contextless and contextual operation. With the former you are traditionally defining an operation for the class, in this case, the defining module. Contextual-operations are something more powerful, because despite being owned by the module, the real objects on which you can invoke that operation are not the own module instance, but others.
As Ed said:
"OCL is going Java-like which is what QVTo might be assumed to do too"
I'm just recalling traditional OOP concepts. Nothing new.
Also note that with a "ALL packages and operations are merged in a simple obvious crunch", you wouldn't ever been able to reuse l1 and l2 at the same time in my example, because how do you merge those conflicting helloWorld() operations ? With the approach I'm exposing, you wouldn't be able to extend both (due to mentioned conflicts), but you would at least been able to access them, as showed above.
Well, we could come up with new inventions, like the order in which you declare the ModuleImport matters, and the operations from last access declaration overrides the previous ones, in case of conflicts, but I don't think that it was the original intention of the specification.
When in the specification you find concepts like "implicit instance", I believe they didn't tend to fall apart from traditional OOP languages.
Cheers,\ Adolfo.
By Christopher Gerking on Oct 23, 2015 10:38
(In reply to Adolfo Sanchez-Barbudo Herrera from comment #8)
- Transformations declare model parameters -> you need to bind model parameters when both, extending (in the module import declaration), and when accessing (when you instantiate the transformation via new).
- Libraries don't declare model parameters -> you would only need to bind model types.
Does this make sense ?
Yes, but if libraries had model params as well, this would offer more flexibility because one could specify specific target extents using the @extent notation. I don't like that concept, but if it is supported inside transformations, it should work for libraries as well (provided that the library params are bound to the params of some base transformation.
Contextless operations actually have a context, the own transformation/library.
Perhaps from a technical viewpoint, but conceptually not. Just like contextual operations, contextless operations are owned by some module. However this doesn't mean that the owning module takes the place of the nonexistent context type.
You don't need to explicitly refer to object (this/self) to invoke a contextless transformation, if and only if they are invoked in the own module. However, if you are accessing another module, you need to refer to the "implicit instance" to be able to invoke them.
Why? Eclipse QVTo demonstrates that there is no technical rationale for that restriction. Also conceptually, it leads to a disparity between contextual and contextless operations, because invocations of contextless operations require an indication of the accessed module, contextual operations don't. I can't reproduce your OOP argumentation. QVTo is more advanced in some places.\
Of course it does matter, because the operation will be called on different kind of objects.
No. Sorry, A and B should represent the containing module of the operations, not the context type. So the actual context object is the same, or might not even exist for a contextless operation.
Also note that with a "ALL packages and operations are merged in a simple obvious crunch", you wouldn't ever been able to reuse l1 and l2 at the same time in my example, because how do you merge those conflicting helloWorld() operations ?
You could still invoke l1::helloWorld() or respectively l2::helloWorld() without specifying an explicit context. No problem.
Did you have a look at how Eclipse QVTo treats a library access? It doesn't have all the limitations that you propose. However I'm not in favor of the Eclipse QVTo handling as well, because I don't see enough differences between accessing and extending a library. If I don't want operation overriding, I can use "extends" and just don't define conflicting operations, no need for "access". Therefore my point of view is that "access" is only beneficial for transformations, whereas "extends" applies to both transformations and libraries.
By Ed Willink on Oct 23, 2015 11:01
Just because Eclipse QVTo does something, does not mean it does it right. The AS is currently unimplementable because it extends the unimplementable OCL AS.
OperationCallExp and PropertyCallExp require a source, therefore I consider that the solution is that the source is a VariableExp referencing the implicit this which is a (Transformation) Class instance. (QVTr/QVTc need this solution too.)
I regard ContextualOperation/ContextualProperty as a fudge that avoided extending the undesigned Complete OCL merge capability. Once Complete OCL is defined as a simple package merge, with simple name-collision rules, QVTo can be simpler. The contextual stuff no longer requires irregular UML concepts owned by the wrong class, instead, the CS just defines an additional Package/Class/Property hierarchy to merge with the regular one. Since these are now regular all the unsolved problems of how a regular PropertyCallExp references an irregular Property go away. Currently Eclipse QVTo does not execute any serious OCL WFRs so the problems are hidden.
By Christopher Gerking on Oct 26, 2015 09:13
(In reply to Ed Willink from comment #10)
Just because Eclipse QVTo does something, does not mean it does it right. The AS is currently unimplementable because it extends the unimplementable OCL AS.
I agree. However I think that the specification is relatively clear at this point, and was also implemented correctly in Eclipse QVTo.\
OperationCallExp and PropertyCallExp require a source, therefore I consider that the solution is that the source is a VariableExp referencing the implicit this which is a (Transformation) Class instance.
Correct. That's how contextless operations can be invoked even if they are contained in an accessed library.
By Adolfo Sanchez-Barbudo Herrera on Oct 26, 2015 11:03
(In reply to comment #11)
OperationCallExp and PropertyCallExp require a source, therefore I consider that the solution is that the source is a VariableExp referencing the implicit this which is a (Transformation) Class instance.
Correct. That's how contextless operations can be invoked even if they are contained in an accessed library.
"implicit this" is not the "implicit instance" of an accessed library.
Again, you shouldn't be able to call context-less operations (operations whose context is the own transformation/library) or contextual properties of accessed modules, unless you have an instance of that transformation/library you can refer. Sorry, but that's an OOP principle, which I don't see any point to change.
As Ed pointed out, if Eclipse QVTo treats operations of accessed modules as they were inherited, it's not doing well with that respect.
Hopefully, this new pointer helps:
"With access semantics, the definitions of the imported module are not inherited by the importing module. Hence an instance of the imported module has to be used in order to access them. In the case of accessing a library, an instance of the imported module is implicitly available. In the case of a non-library module, the instance of the accessed module is to be created explicitly (see Clause 8.2.2.22\ “InstantiationExp”)."
This clearly supports the rationale I exposed before. However, the only problem in the specification is that despite having "an instance implicitly available" for accessed libraries, we don't have syntax to declare a name for that implicitly created instance, to be able to refer to it later on when we need to invoke an operation or access a property of it. The solution proposed above cures that.
(In reply to comment #10)
I regard ContextualOperation/ContextualProperty as a fudge that avoided extending the undesigned Complete OCL merge capability. Once Complete OCL is defined as a simple package merge, with simple name-collision rules, QVTo can be simpler.
Yes, I think you are right. If OCL already deals with additional contextual properties and definitions in that way, I see no point why they should be managed in a different one in QVT. Something to consider in the Pivot-based QVTo implementation.
By Christopher Gerking on Oct 26, 2015 12:06
(In reply to Adolfo Sanchez-Barbudo Herrera from comment #12)
"implicit this" is not the "implicit instance" of an accessed library.
It's not necessarily "this". To be honest I don't even know if it is really "this" in Eclipse QVTo, but it is definitely some implicit variable that is bound to the library instance.
Again, you shouldn't be able to call context-less operations (operations whose context is the own transformation/library) or contextual properties of accessed modules, unless you have an instance of that transformation/library you can refer.
The instance exists. Why is there a need to refer to it explicitly? In Java the "this" reference is also optional.
Sorry, but that's an OOP principle, which I don't see any point to change.
I don't see where my argumentation breaks that principle. The only difference I see is that the library instance is implicit only, i.e., there is no way to refer to it explicitly.
If we are stressing that principle in its entirety, why should contextual operations from an accessed library be available? When invoking them, we do not refer to the implicit library instance at all, so why should they be accessible from an OOP viewpoint?\
As Ed pointed out, if Eclipse QVTo treats operations of accessed modules as they were inherited, it's not doing well with that respect.
It doesn't. The point is: what means "inherited" ? I argue that they are not inherited, because you can't override them. They are just available by the use of an implicit source variable.
Ed also pointed out that the usage of the containing module as the operation context is merely a hack to make these operations invokable using an OperationCallExp. That's an implementation issue which shouldn't affect the specification.\
This clearly supports the rationale I exposed before.
In what way? I interpret this snippet as a relatively clear specification of what Eclipse QVTo currently implements. There is an implicit variable for each accessed library, that may act as an implicit source for operation calls or property navigations. There is no implicit variable for an accessed transformation, because it needs to be instantiated explicitly.
However, the only problem in the specification is that despite having "an instance implicitly available" for accessed libraries, we don't have syntax to declare a name for that implicitly created instance, to be able to refer to it later on when we need to invoke an operation or access a property of it. The solution proposed above cures that.
Defining an explicit syntax is of course fine, though. Do you have a concrete example in mind where the implicit variable is not sufficient?
By Adolfo Sanchez-Barbudo Herrera on Oct 26, 2015 12:45
Hi Christopher,
"this" is the own module rather than "another" you are accessing.
When you are writing "a()" you are unambiguously doing "this.a()", the own module. You can't write "a()" to access an operation/property of another class/accessed module. Again think of OOP/Java. You need the name of the implicit variable comprising the object/instance on which you are gonna operate, in order to call its operations and properties. i.e. you have to write "another.a()".
There is an example of "this." usage at the end of 8.1.18. That said, I believe that an extra clarification could be added.
You might have 100 implicit variables, corresponding to 100 accessed library instances, but if you don't have the names to refer to them, you are sold to invoke their (context-less) operations/properties defined in it.
(In reply to comment #13)\
Defining an explicit syntax is of course fine, though. Do you have a concrete example in mind where the implicit variable is not sufficient?
In comment 8, I exposed an example with l3 library in which a variable name is explicitly given for the implicitly created instance of the accessed libraries (l1 and l2). Once you have a name, you can properly refer to the implicitly created instance to invoke any of its operations/access any of its properties.
The syntax I proposed is just an addition I've made and to be used in scenarios 3) and 7). We can argue if a better/different one should be used.
Regards,\ Adolfo.
By Christopher Gerking on Oct 26, 2015 13:13
(In reply to Adolfo Sanchez-Barbudo Herrera from comment #14)
"this" is the own module rather than "another" you are accessing. When you are writing "a()" you are unambiguously doing "this.a()"
Not so in Java, see below.
You can't write "a()" to access an operation/property of another class/accessed module. Again think of OOP/Java.
What about nested classes? The following Java snippet invokes a() without an explicit source, whereas the implicit source is precisely not "this" but "A.this" which is a different object.
public class A {
public void a() {}\
\
class B {\
public void b() {\
a();\
}\
} \
}
As you can see there can even be multiple "thisses". The question is whether accessed libraries require a syntactic distinction (such as in Java) or can all reuse the "this" syntax. Arguable.
You need the name of the implicit variable comprising the object/instance on which you are gonna operate, in order to call its operations and properties.
The sense behind an implicit variable is that I don't need to specify that name reference when invoking operations or navigating properties.
You might have 100 implicit variables, corresponding to 100 accessed library instances, but if you don't have the names to refer to them, you are sold to invoke their (context-less) operations/properties defined in it.
I can write this.A::a() and this.B::a() in order to distinguish. I consider "this.A" as something similar to Java's "A.this" mentioned above.
By Ed Willink on Oct 26, 2015 13:58
Java has multiple thises sometimes. Other times you have do disambiguate with X.this.
QVTo can automatically insert the appropriate myLibThis for a() if it is unambiguous. But if you really have a 100 libraries you can expect some ambiguities that will need explicit resolution, so perhaps the spelling of the hidden myLibThis should be specifiable in an extended import statement.
e.g.
library myUML : MyUmlFacilities(UML)
allows myUML.a() to be used as a disambiguation.
By Christopher Gerking on Oct 28, 2015 05:03
(In reply to Ed Willink from comment #16)
Java has multiple thises sometimes. Other times you have do disambiguate with X.this.
QVTo can automatically insert the appropriate myLibThis for a() if it is unambiguous. But if you really have a 100 libraries you can expect some ambiguities that will need explicit resolution, so perhaps the spelling of the hidden myLibThis should be specifiable in an extended import statement.
e.g.
library myUML : MyUmlFacilities(UML)
allows myUML.a() to be used as a disambiguation.
Provided that we really require a new syntactical distinction, I prefer Adolfo's approach of specifying the name as part of the ModuleImport ("access") declaration, rather than during the declaration of the accessed library itself:
(In reply to Adolfo Sanchez-Barbudo Herrera from comment #8)
---- lib3.qvto ----
import lib1.qvto; import lib2.qvto;
library l3 access a : l1, access b : l2 ;
But is it really needed? In case of 100 imports by access, there are 100 implicit variables. If we want to invoke an operation a() from a specific accessed library named MyUmlFacilities, we can write MyUmlFacilities::a(). This will lead to a search for the one implicit variable that represents an instance of MyUmlFacilities. There is just one possibility, because every library should be accessed at most once. No new syntax required.
By Ed Willink on Oct 28, 2015 05:43
(In reply to Christopher Gerking from comment #17)
accessed library named MyUmlFacilities, we can write MyUmlFacilities::a().
You could be arguing then that the Library features are "static". This is supported by UML, and was added in OCL 2.2 without any editorial clarification so it is still undecided whether the source of a static Property/OperationCallExp is null or some magic such as a VariableExp for a "this".
For Eclipse OCL/QVTo this remains academic since Ecore does not support static features.
A magic VariableExp is more regular and bypasses the Ecore limitation.
A new syntax is not necessary since qualification can be used, but allowing a more friendly name seems desirable.
By Adolfo Sanchez-Barbudo Herrera on Oct 28, 2015 09:32
Hi All,
It seems we are finally aligning in this
I agree that technically is not mandatory, as you could try to infer if an operation belongs to a implicitly created instance created during the module import declaration, but:\ a) This is a kind of additions to what Java, for instance , does and it makes the resolution of operation calls harder and probably slower.\ b) It´s yet unclear to me if this enhancement also applies to "not implicit variables", that means to any library or transformation we explicitly instantiate. Do we want to disitinguish in the AS between implicit variables and those which are not ?\ b) If two files imported two modules with the same name, makes the FQN even less desirable, you not only had to qualify with the name the file each accessed module, but also every possible ambiguous.
It seems we ALLagree on allowing to define a variable for the implicit accessed library instance is good. However, I´m unclear if we should prohibit resolve operation calls "a()" and property calls "debugMode" belonging to an accessed library. AFAIU:
Jumping to another of the pending topics:
When a transformation extends another transformation (scenario 2) ), I think we agree that there should be model parameters bindings between the extending and the extended transformation.
This is not supported in the AS.
In terms of CS, some examples are definitely needed.
In terms of CS, just wondering about your position of supporting to refer to ModelTypes whenver you can infer the ModelParameter. This is just to support the syntax that currently appears in the spec:
transformation UmlCleaning(inout umlmodel:UML14)\ extends MyUmlFacilities(UML14)
Regards,\ Adolfo.
By Ed Willink on Oct 28, 2015 09:53
(In reply to Adolfo Sanchez-Barbudo Herrera from comment #19)
- I´m unclear about Ed´s position.
So am I.
It would be very helpful to have a perhaps 20 line example to analyze that demonstrates the syntax/semantic challenges.
By Christopher Gerking on Oct 28, 2015 11:08
(In reply to Adolfo Sanchez-Barbudo Herrera from comment #19)
a) This is a kind of additions to what Java, for instance , does and it makes the resolution of operation calls harder and probably slower.
Don't you think that Java's handling of nested class instances represents quite a similar concept? Anyway, we are not encouraged to follow Java entirely. I agree that some explicit mechanism to speed up the implicit inference might be useful, but why is an invocation like MyAccessedLibrary::a() insufficient? An efficient implemantation would map MyAccessedLibrary to its implicit instance, and so provide very fast access during the CS analysis.
b) It´s yet unclear to me if this enhancement also applies to "not implicit variables", that means to any library or transformation we explicitly instantiate. Do we want to disitinguish in the AS between implicit variables and those which are not ?
Which enhancement do you mean?
It seems we ALLagree on allowing to define a variable for the implicit accessed library instance is good.
It's good as long as there is a use case which requires it. Right now I still feel as if qualifying the operation call with the owning module does alraedy the trick. See the above invocation using MyAccessedLibrary::a(). The same applies to contextual operation invocations using this.MyAccessedLibrary::a().
There is one use case I can imagine which is passing the accessed library instance itself as a parameter to an operation. Implicit variables are restricted to the source of an operation call. So if this is a valid use case, we would indeed require an explicit name for the accessed library instance. IMHO it isn't a plausible use case, though.
When a transformation extends another transformation (scenario 2) ), I think we agree that there should be model parameters bindings between the extending and the extended transformation.
Yes, but again: why excluding libraries here? They might require model parameters as well in order to attach an instantiated element to a particular extent, or to query elements from a model extent.\
This is not supported in the AS.
Yes, is there an OMG issue yet?
transformation UmlCleaning(inout umlmodel:UML14) extends MyUmlFacilities(UML14)
This is quite pointless. UML14 is a modeltype. Why passing a modeltype to a module during instantiation? A module already declares modeltypes on its own.
| --- | --- | | Bugzilla Link | 480202 | | Status | NEW | | Importance | P3 normal | | Reported | Oct 20, 2015 08:20 EDT | | Modified | Oct 28, 2015 11:08 EDT | | Reporter | Adolfo Sanchez-Barbudo Herrera |
Description
Coming from initial discussion: Bug 468367
In general a Module can "import" other Modules, where a ModuleImport is created in the importing transformation, specifying the kind of import (access or extends), as well as some ModelType bindings.
Providing we have Libraries and Transformations we can have the following 8 possibilities. I list them, highlighting those which explicitly appear in the spec as examples:
1) Transformation access Transformation (e.g. in Page 71) 2) Transformation extends Transformation (e.g. in Page 71) 3) Transformation access Library (e.g. in Page 82) 4) Transformation extends Library (e.g. in Page 82) 5) Library access Transformation 6) Library extends Transformation 7) Library access Library (e.g. in Page 83) 8) Library extends Library (e.g. in Page 83)
I didn't find any example for 5) and 6) and probably they should not be supported. Rationale: If a library doesn't define model parameters (some comments about this below), we won't probably be able to instantiate an accessed transformation or extend it.
Other interesting facts I can find on this topic:
9) "A library contains definitions that can be reused by transformations" (Page 64). Having 7) and 8), "reused by other modules" seems more accurate.
10) "It may define specific types and may define operations (like query operations or metaclass constructors)" (Page 64). What about helpers and mappings ? I found no example in the spec demonstrating that helpers/mappings can be defined in a library. I only found some queries definitions. In principle, it sounds like an unnecessary limitation and both helpers/mapppings should be allowed. Not a contradiction since they are "operations". Apparently, Eclipse QVTo works with mappings defined inside libraries.
11) "A library may declare an ordered list of model types on which it operates. This list is the signature of the library." (Page 83). Interpretation of this is aligned with one of the Christopher comments: "A library doesn't have ModelParameters". If there are no model parameters, two comments:\ a) Library "signature" is confusing. \ b) Indeed, a library can always be implicitly instantiated without hassles (we don't need to pass model extents to it).\ c) Helpers and mappings should then be prohibited in libraries (see 10)) because if an element is created we don't know to which model extent should belong (I'm not sure if we should enter in this mess without firstly sorting out the issue about model extents, but as of the current specification created elements should belong to an extent related to a model parameter).
12) "A library is like a Java class where all the declared properties and declared operations of the library are effectively attribute slots and methods of the class. However, in contrast with operational transformations there is no main operation to execute and the instantiation of the class is always implicit" (Page 83). One could interpret, that a library is just a non-invokable OperationalTransformation, but this interpretation might be in conflict with other possible interpretations e.g. a library should not contain helpers and mappings.
13) "A library is a module grouping a set of operations and type definitions that are put together for reuse. The QVT Standard Library is an example of a Library instance. All but the QVT Standard Library must be explicitly imported." (Page 83). Conceptually the StdLib is just a simple Library which is implicitly imported. But how is that library defined ? Are all the operations defined as side effects-full helpers or side effects free queries? What about operations like clone which create elements ? Are we in contradiction of 10) providing that helpers or mapping might not be allowed in a library ?
14) "When a library is imported with access semantics, an implicit instance is created and used to access the properties and operations of the library" (Page 83) and "With access semantics, the definitions of the imported module are not inherited by the importing module. Hence an instance of the imported module has to be used in order to access them. In the case of accessing a library, an instance of the imported module is implicitly available" (Page 85). We have this concept of "implicit" instance which needs to be accessed: "use" or "access" the "implicit" instance is confusing. Accessing the instance is necessary if there is any property or non-contextual operation to be accessed. Perhaps, when accessing a library, you can only invoke contextual imperative operations. If you need to access or invoke a non-contextual property of a library, you need to "extend" it rather than "access" it.
Before jumping to other important concerns such as the bindings of ModuleImport, I think we have enough material to discuss.
I think that the critical points are. 10) and 11), having 13) as an important one to take a decision about the the formers. Looking forward to hearing your points of view about this (Please refer to the numbers when discussing).
Cheers,\ Adolfo.