Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Query with Set can be evaluated with Query Results but generated code does not compile #125

Open
eclipse-viatra-bot opened this issue Mar 12, 2024 · 9 comments
Labels
bugzilla Issues migrated from Eclipse bugzilla. Query Issues related to the query component of VIATRA, including runtime or pattern language issues.

Comments

@eclipse-viatra-bot
Copy link

| --- | --- |
| Bugzilla Link | 564426 |
| Status | UNCONFIRMED |
| Importance | P3 normal |
| Reported | Jun 18, 2020 09:12 EDT |
| Modified | Dec 07, 2020 12:56 EDT |
| Version | 2.3.2 |
| Reporter | Hans van der Laan |

Description

The following query can be evaluated with the Query Results View:

pattern SetTestQuery(myresult: java Set) {
myresult == eval(new HashSet());
}

However, the generated code does not compile. In three places in the generated code, a reference to a generic is added which can not be resolved.

Generated Code:

public final class SetTestQuery extends BaseGeneratedEMFQuerySpecification<SetTestQuery.Matcher> {

[…]

public boolean set(final String parameterName, final Object newValue) {\
  if (!isMutable()) throw new java.lang.UnsupportedOperationException();\
  if ("myresult".equals(parameterName) ) {\
      this.fMyresult = (Set<E>) newValue;   <== “Cannot resolve symbol 'E'”\
      return true;\
  }\
  return false;\
}\
\

[…]

protected Stream<Set<?>> rawStreamAllValuesOfmyresult(final Object[] parameters) {\
  return rawStreamAllValues(POSITION_MYRESULT, parameters).map(Set<E>.class::cast); <== “Cannot resolve symbol 'E'\
}\
\

[…]

@OverRide
public SetTestQuery.Match newMatch(final Object... parameters) {
return SetTestQuery.Match.newMatch((java.util.Set) parameters[0]); <== “Cannot resolve symbol 'E'
}
}

If you remove the everywhere, the code compiles and the pattern seems to works.

@eclipse-viatra-bot eclipse-viatra-bot added bugzilla Issues migrated from Eclipse bugzilla. legacy Query Issues related to the query component of VIATRA, including runtime or pattern language issues. labels Mar 12, 2024
@eclipse-viatra-bot
Copy link
Author

By Zoltan Ujhelyi on Jun 19, 2020 10:48

This is another untested area of our infrastructure: we are not really using generic classes in VIATRA, so you have stepped on a related mine.

I will try to do a quick fix for this issue that omits the generic type parameters; it would be better to completely support generics in VQL, but that seems unnecessary.

Until a fix is available, could you work around the issue by explicitly erasing the generic types from the expression (with casting if necessary)?

@eclipse-viatra-bot
Copy link
Author

By Hans van der Laan on Jun 22, 2020 04:21

Thanks! Manually editing the generated pattern files after every recompile is quite annoying :)

Can we cast in evaluation expressions? If I try to do something like:

groups == eval( (Set<Object>) gr);

I get the following errors:

[ERROR] ERROR:no viable alternative at input ')' (file:/C:/Users/hans.vanderlaan/shared-workspace/trbac-verifier/com.vanderhighway.trbac.verifier/src/main/java/com/vanderhighway/trbac/verifier/PolicyQueries.vql line : 232 column : 30)
[ERROR] ERROR:extraneous input 'gr' expecting ')' (file:/C:/Users/hans.vanderlaan/shared-workspace/trbac-verifier/com.vanderhighway.trbac.verifier/src/main/java/com/vanderhighway/trbac/verifier/PolicyQueries.vql line : 232 column : 32)
[ERROR] ERROR:< cannot be resolved. (file:/C:/Users/hans.vanderlaan/shared-workspace/trbac-verifier/com.vanderhighway.trbac.verifier/src/main/java/com/vanderhighway/trbac/verifier/PolicyQueries.vql line : 232 column : 22)

If I try to set the type in the pattern definition, I get a similar error:

pattern my_pattern(groups: java Set<Object>) 

[ERROR] ERROR:mismatched input '<' expecting ')' (file:/C:/Users/hans.vanderlaan/shared-workspace/trbac-verifier/com.vanderhighway.trbac.verifier/src/main/java/com/vanderhighway/trbac/verifier/PolicyQueries.vql line : 235 column : 52)

@eclipse-viatra-bot
Copy link
Author

By Zoltan Ujhelyi on Jun 22, 2020 04:37

(In reply to Hans van der Laan from comment #2)

Thanks! Manually editing the generated pattern files after every recompile
is quite annoying :)

Can we cast in evaluation expressions? If I try to do something like:

groups == eval( (Set) gr);

This syntax is a Java-like casting, but Xbase (and thus the check expressions) use a different syntax. You could try something like

groups == eval(gr as Set);

@eclipse-viatra-bot
Copy link
Author

By Hans van der Laan on Jun 22, 2020 08:06

Oh, haha. I read over the part in the manual that not Java but Xbase is used in the the eval expressions.

Rewriting the patterns as:

pattern my_pattern(groups: java Set) {
find foo(gr);
groups == eval(gr as Set);
}

OR

pattern my_pattern(groups: java Set) {
find foo(gr);
groups == eval(gr as Set);
}

does not solve the issue.

@eclipse-viatra-bot
Copy link
Author

By Zoltan Ujhelyi on Jun 22, 2020 10:46

I see. Sorry, this means I cannot provide you with any workaround here. I'll try to figure something out as soon as possible.

@eclipse-viatra-bot
Copy link
Author

By Gabor Bergmann on Jun 22, 2020 11:38

Note: before we fix the issue, I may have 2 quick workarounds for you.

Idea 1. If you can live without the pattern-specific generated matches/match classes, you can turn off this feature of the code generation in Preferences / VIATRA / Query Language / Compiler / Pattern-specific matcher generation strategy. In that case the generated code is less fully featured from a usability standpoint, and will force you to use the generic (pattern-independent) query API, but it should compile at least :)

Idea 2: if you happen to have full control over how these sets are created in the first place, you can just create a new non-generic class:

class HansIntegerSet extends HashSet

and then instantiate/use HansIntegerSet everywhere in query queries.

A further remark: while you have indeed found a bug, are you sure you really need set-valued variables to achieve your goal? Legitimate use cases do exists, but more often than not, they are a "smell", an indicator of badly designed queries. For instance, if you want to associate a person with the set of their university degrees, then instead of:

pattern hasDegrees(owner: Person, degrees: Set) {...}

you could have:

pattern hasDegree(owner: Person, degree: Degree) {...}

This is the idiomatic way to represent a one-to-many or many-to-many relationship in Viatra, since it has Set/Relation semantics anyway. You can then always ask the matcher to give you all degrees a given person owns, or all persons who own a given degree.

@eclipse-viatra-bot
Copy link
Author

By Hans van der Laan on Jun 24, 2020 02:54

I have full control on how my sets are made, so I think option 2 would work. That’s a really smart yet simple work around! :)

I don’t need set-valued variables per se, I could also use something else. However, I thought it would be the nicest way to solve the issue.

My use case from an abstract point of view:

We have scenario’s, attributes and properties:

Scenarios <-> Attributes <-> Properties

Scenarios have attributes. Based on the set of attributes associated with the scenario, certain properties hold about that scenario. There are a lot of scenario’s, many of which are the same. Scenarios can have duplicate attributes. I want to check if all scenarios respect some constraints. These constraints are based on the derived properties.

For example, Imagine that we have:

scenario_attribute(s1, a1)
scenario_attribute(s1, a2)
scenario_attribute(s1, a2)
scenario_attribute(s2, a1)
scenario_attribute(s2, a3)
scenario_attribute(s3, a3)
scenario_attribute(s4, a3)

Which gives us:
scenario_property(s1, p1)
scenario_property(s1, p2)
scenario_property(s2, p1)
scenario_property(s2, p1)
scenario_property(s3, p1)
scenario_property(s4, p1)

Now, I want to know what are the possible groups of attributes/properties, e.g.
distinctAttributesGroup({a1,a2,a3})
distinctAttributesGroup({a1,a3}
distinctAttributesGroup({a3})

and through some logic, we find that
distinctPropertyGroup({p1, p2})
distinctPropertyGroup({p1})

Given that I have this, if I link scenarios to an distinctAttributeGroup, which in turn I link to a distinctPropertiesGroup, I don’t have to check my constraints for each scenario. Instead, I can check them for each disctinctPropertiesGroup. This will speed up the checking, as the size of DisctinctPropertiesGroups is much smaller then the number of scenarios . However in my patterns, I still need (sub)patterns such as:

distinctPropertyGroupHasProperty({p1, p2}, p1)
distinctPropertyGroupHasProperty({p1, p2}, p2)
distinctPropertyGroupHasProperty({p1}, p1)

to prove the properties. Thus, I basically use the set as identifier for the abstract property groups. Therefore, I could also make a method which creates an unique string-based ID based on the set. As far as I see it I need some kind of aggregator to make an unique ID based on a one-to-many relation, but I don’t need a Set per se. I could also use a String.

(NOTE: Thus, my aggregator is a "distinct" operator which, given a multiset of elements, returns the set of unique elements. )

@eclipse-viatra-bot
Copy link
Author

By Gabor Bergmann on Jun 24, 2020 15:51

OK, this sounds like one of those legitimate use cases where Set-typed fields are really useful.

Regarding your aggregator: are you aware that Viatra has set-based semantics anyway? (= results are match SETS) So this "flattening of multisets" happens automatically? E.g. the following pattern will have a single match:

pattern scenario_attribute(s, a) {
s == "a1";
a == "a2";
} or {
s == "a1";
a == "a2";
} // same match, will not be counted twice

The input to an aggregator is a multiset, but only because it takes a single column of a relation, so the same value might occur multiple times per aggregation group.

FYI you might be interested to hear that a new feature is currently in development that could help you even further. eval unwind will allow you to fill a single variable the individual members of a set, each in a separate match.

https://git.eclipse.org/r/#/c/154735/

The new language element is actually mostly ready, but as you can see, there is very little documentation right now and no functional tests yet. Also, there is only a single very simplistic example: https://git.eclipse.org/r/#/c/154735/8/documentation/org.eclipse.viatra.documentation.help/src/main/asciidoc/releases/viatra-2.4.adoc

@eclipse-viatra-bot
Copy link
Author

By Hans van der Laan on Jun 25, 2020 03:37

That looks very interesting! :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bugzilla Issues migrated from Eclipse bugzilla. Query Issues related to the query component of VIATRA, including runtime or pattern language issues.
Projects
None yet
Development

No branches or pull requests

2 participants