viatra / EMF-IncQuery

This repository is only kept for historic reasons. All development happens on eclipse.org
http://eclipse.org/viatra
13 stars 4 forks source link

Add * operator to pattern language #350

Closed abelhegedus closed 11 years ago

abelhegedus commented 11 years ago

The * operator would work like the + operator, but it would contain the element itself even if there is no self-loop or loop.

Consider the example (taken and simplified from https://github.com/ujhelyiz/EMF-IncQuery/blob/query-backed-features/plugins/org.eclipse.viatra2.emf.incquery.ecore.derived/src/org/eclipse/viatra2/emf/incquery/ecore/eclass/EClassDerivedFeatures.eiq):

private pattern thisAndAllSuperTypes(This : EClass, Target : EClass){
    find superTypes+(This, Target);
} or {
    This == Target;
}

pattern eAllStructuralFeatures(This : EClass, Target : EStructuralFeature){
    find thisAndAllSuperTypes(This, Type);
    find eStructuralFeatures(Type, Target);
}

would be instead:

pattern eAllStructuralFeatures(This : EClass, Target : EStructuralFeature){
    find superTypes*(This, Type);
    find eStructuralFeatures(Type, Target);
}

Pros:

Cons:

Consider a more complex example:

This could be written now as:

pattern modelForElement(E: Element, M : Model) {
  Model.containers(M, E);
} or {
  Model.containers(M, B);
  find subContainers+(B,E);
} or {
  Model.containers(M, B);
  find subContainers+(B,C);
  Container.components(C, E);
}

And could be written as:

pattern modelForElement(E : Element, M : Model){
  Model.containers(M,C);
  find subcontainers*(C, SC); // although C may not have subContainers, it can be equal to SC
  find components*(SC, E); // although SC might not include any components, it can be equal to E
}
bergmanngabor commented 11 years ago

Con: unfeasability.

 pattern problematic(A,B) { find whatever*(A,B) } 

would have an infinite match set, since everything must be included with a self-loop.

The path expression version (see daydreams in #8) would be more feasible, because then we would have a type range:

 Model.containers.subcontainers*.components?(M,E)

(but even this is unsure - should it be the intersection of source and target types maybe?) BTW in the latter I also demonstrate the hypothetical ? path expression operator, which is closer to what you need there.

abelhegedus commented 11 years ago

Obviously, more powerful path expressions would be way better.

However, your example, imho is not unfeasible, only really bad for memory and performance. That is why we would need to add validators to ensure, that * is only possible if the parameter type is NOT Object. And probably something similar to cartesian products to tell the user to add additional constraints to the problematic query.

bergmanngabor commented 11 years ago

Ok, so let's assume there is a pattern abc(d:E, f:G) {...}, what should be listed as a self-loop in the match set of find abc*(X,Y)? All elements X==Y of type E, or G, or E intersect G maybe?

abelhegedus commented 11 years ago

Yes, "All elements X==Y of type E, or G, or E intersect G" with the addition "that exist in the model". I don't ask EIQ to list all possible Integers (or Strings...).

We would have the same match set if we write a pattern like:

pattern EF(x){
  E(x);
} or {
  F(x);
}

While the usecases where I would find it useful have further constraints to ensure that the actually used patterns have less matches.

bergmanngabor commented 11 years ago

Yes, "All elements X==Y of type E, or G, or E intersect G maybe?"

--> well, which one?

However, the code you suggested: pattern EF(x){ E(x); } or { F(x); } would imply the type E union G instead, which has a major con: in case of find abc*(X,Y), the type inferencer would find E union G for the type of X, instead of E as for find abc(X,Y) or find abc+(X,Y). Remember that we have had problems with type checking union types.

From the point of view of the type checker, the best answer would be to put self loops on elements of E intersect G, so that the type of X could be E and the type of Y could be G.

with the addition "that exist in the model". I don't ask EIQ to list all possible Integers (or Strings...).

Yeah, E and G would have to be EClassifiers.

While the usecases where I would find it useful have further constraints to ensure that the actually used patterns have less matches.

I can't understand what you are saying.

abelhegedus commented 11 years ago

I agree with the following constraints:

For the other part, I meant that pattern problematic(A,B) { find whatever*(A,B) } is not one of my typical use cases :smiley:

bergmanngabor commented 11 years ago

For the other part, I meant that pattern problematic(A,B) { find whatever*(A,B) } is not one of my typical use cases

Well, if the star operator is not a typical use case, then why add it to the language? Or if you are specifically referring to the fact that there are no other constraints, do we want to change the semantics of the star operator based on what other constraints are there?

abelhegedus commented 11 years ago

Well, if the star operator is not a typical use case, then why add it to the language?

It is not as often needed as path expression but almost as often as the regular transitive closure.

Or if you are specifically referring to the fact that there are no other constraints, do we want to change the semantics of the star operator based on what other constraints are there?

No, I merely commented that in a typical use case, there would be other constraints in the pattern and that we can add validation that warns the user if this is not true.

istvanrath commented 11 years ago
abelhegedus commented 11 years ago

Thanks for the useful comment :smiling_imp:

istvanrath commented 11 years ago

Can this one be migrated to Eclipse @abelhegedus ?

abelhegedus commented 11 years ago

I think we can close this, as @bergmanngabor raised some valid points and existing enhancements already cover a similar case.